{"title":"Whiskey and Code","subtitle":"Shawn Oster's personal blog and wiki, with occasional whiskey","updated":"2026-10-18T02:42:07+00:00","id":"https:\/\/whiskeyandcode.com\/","link":[{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/"}},{"@attributes":{"rel":"self","type":"application\/atom+xml","href":"https:\/\/whiskeyandcode.com\/atom.xml"}}],"author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode.com\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","generator":"Hugo","entry":[{"title":"Exploring Solo and Card-Based RPGs","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/exploring-solo-and-card-based-rpgs\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/exploring-solo-and-card-based-rpgs\/","updated":"2026-10-18T02:41:51+00:00","published":"2023-09-14T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"The Rabbit Hole I went down a solo and standard playing card RPG rabbit hole after playing &ldquo;The Wolves of Langston&rdquo;, a 5e D&amp;D solo adventure. I had a blast sitting at the table with some whiskey, a character sheet, and my tablet and after my first play-thru I wanted more.","content":"<h2 id=\"the-rabbit-hole\">The Rabbit Hole<\/h2>\n<p>I went down a solo and standard playing card RPG rabbit hole after playing &ldquo;<a href=\"https:\/\/obviousmimic.com\/en-us\/products\/the-wolves-of-langston-solo-adventure-rpg-pdf-epub\">The Wolves of Langston<\/a>&rdquo;, a 5e D&amp;D solo adventure. I had a blast sitting at the table with some whiskey, a character sheet, and my tablet and after my first play-thru I wanted more. I started with the PDF but recommend a hard copy for that old school feel.<\/p>\n<p>I was left wanting more, as well as curious about non-dice mechanics and pining for something with a mapping aspect since I&rsquo;m a sucker for grid paper, a ruler and a new mechanical pencil.<\/p>\n<ul>\n<li><a href=\"https:\/\/boardgamegeek.com\/boardgame\/197097\/four-against-darkness\">Four Against Darkness<\/a> is a light dungeon crawler where you control four characters and roll for room shape, contents, and possible monsters, treasure, traps. Combat is fun and crunch-light. Tons of supplements and derivative works for different settings\/themes, character levels, monsters, and expanded tables.<\/li>\n<li><a href=\"https:\/\/boardgamegeek.com\/boardgame\/237031\/d100-dungeon\">D100<\/a> is similar but you&rsquo;re a single character and combat is much crunchier with damage and gear per body part, with the ability to repair armor. I played a bit but got more into <a href=\"https:\/\/boardgamegeek.com\/boardgame\/367485\/d100-space\">D100 Space<\/a>.<\/li>\n<\/ul>\n<p>Then I remembered a solo RPG Kickstarter I backed, <a href=\"https:\/\/www.ironswornrpg.com\/\">Ironsworn<\/a>. The system is fun but since I&rsquo;m not a fan of low fantasy (give me magic! give me elves!) I didn&rsquo;t play it much BUT he did release a sci-fi version that&rsquo;s very Firefly\/Star Wars aligned called <a href=\"https:\/\/www.ironswornrpg.com\/product-ironsworn-starforged\">Starforged<\/a> so I bought that and played a bit and it was a BLAST.<\/p>\n<p>Next, as someone that goes through a deck of cards a week due to constant shuffling and fidgeting I wondered if anyone had incorporated a standard deck into an RPG. The answer is yes. I checked out non-solo RPGs that use playing cards and really liked the world building and weirdness of <a href=\"https:\/\/rowanrookanddecard.com\/product\/unbound\/\">Unbound<\/a> and may steal some of the ideas for other games. It moves a lot of the world building out of GM prep and into the session zero as as group activity, with each person rolling a random world aspect that the group then weaves into a cohesive setting.<\/p>\n<p>Another set of tables generates a shared core truth that binds the group together, followed by individual goals that others can suggest for your character. It&rsquo;s just prescriptive enough to give the group a focus yet wildly open to how they achieve it.<\/p>\n<h2 id=\"index-card-rpg\">Index Card RPG<\/h2>\n<p>That led me to <a href=\"https:\/\/www.modiphius.net\/en-us\/products\/index-card-rpg-master-edition\">Index Card RPG<\/a>, which uses the classic six dice and stats but uses index cards to map out the adventure, with each index card representing a single location, reward, or situation, with a single value to use for all checks. One card might be a goblin camp that you have to move through, with a target check of 12. Want to go full murder hobo, beat a 12. Your bard craving some strange, clear a 12 for that sweet cross-species debauchery.<\/p>\n<p>The target value can be adjust down by -3 (EASY) or up +3 (HARD), depending. That frisky bard recognizes some chill goblins from the last Fire Goblin festival (like Burning Man but cleaner), drop the 12 to 9. The murder hobos forget they were cursed by a peddler they swindled, that the next time they raised their weapons against the innocent their weapons would turn into flower bouquets and their armor into pastry dough, bump that 12 to 15.<\/p>\n<p>While adventures are prepped with key locations players can still go off script. If they decide the wizard wasn&rsquo;t paying them nearly enough to deal with horny goblins they can do the usual role-playing and once they pick their next move the GM can whip up a new card with the next encounter.<\/p>\n<p>Less pouring over characters sheets for that one magic skill or spell and more creativity in the approach. Probably less fun for min\/maxers that enjoy spec&rsquo;ing out the ultimate killing machine. That&rsquo;s what Baulder&rsquo;s Gate is for.<\/p>\n<h2 id=\"dungeon-solitaire\">Dungeon Solitaire<\/h2>\n<p>And that brings us to what I really wanted to share, <a href=\"https:\/\/matthewlowes.com\/games\/\">Dungeon Solitaire<\/a> (scroll down a bit on the page), a relaxing solo card-based fantasy adventure loosely based on the classic solitaire layout that uses a scoring system based on how much &ldquo;treasure&rdquo; you escape with to create tension. And you must escape, if you die or your torches go out, no points for you.<\/p>\n<p>Just like solitaire it&rsquo;s easy to mindlessly play once you know the mechanics.<\/p>\n<p>There&rsquo;s a slightly deeper system that uses tarot cards that I might try. Or I might spend the next three years perfecting my own highly stylized version, at least talking about it :)<\/p>\n<p>May all your rolls be interesting&hellip;<\/p>","category":[{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/categories\/whiskey\/","term":"Whiskey","label":"Whiskey"}},{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/tags\/rpg\/","term":"Rpg","label":"Rpg"}},{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/tags\/solo\/","term":"Solo","label":"Solo"}}]},{"title":"How to Love Markdown","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/why-i-love-markdown\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/why-i-love-markdown\/","updated":"2026-10-18T02:41:51+00:00","published":"2022-08-09T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"Markdown Overview Welcome to a quick tour of Markdown, where it came from, why I love it, how to use it.\nWhat is Markdown? The official Daring Fireball site offers a much better overview of what Markdown is. The short version is that Markdown is a markup domain-specific language (DSL) designed to be human-readable that can also be rendered into semantically correct XHTML.","content":"<h1 id=\"markdown\">Markdown<\/h1>\n<h2 id=\"overview\">Overview<\/h2>\n<p>Welcome to a quick tour of Markdown, where it came from, why I love it, how to use it.<\/p>\n<h2 id=\"what-is-markdown\">What is Markdown?<\/h2>\n<p>The <a href=\"https:\/\/daringfireball.net\/projects\/markdown\/\" title=\"Daring Fireball\">official Daring Fireball site<\/a> offers a much better overview of what Markdown is. The short version is that Markdown is a markup domain-specific language (DSL) designed to be human-readable that can also be rendered into semantically correct XHTML.<\/p>\n<p>The core tenet ripped straight from Daring Fireball:<\/p>\n<blockquote>\n<p>Readability, however, is emphasized above all else. A Markdown-formatted document should be publishable as-is, as plain text, without looking like it\u2019s been marked up with tags or formatting instructions.<\/p>\n<\/blockquote>\n<p>Due to its concise yet natural syntax and easy readability as plain text, it has become the de facto standard in most community forums (Reddit, StackOverflow), blogging and documentation platforms (Hugo, Jekyll, readthedocs.io), and every online wiki.<\/p>\n<p>All modern editors support it some form, from syntax highlighting, live previews, and <a href=\"https:\/\/github.com\/DavidAnson\/vscode-markdownlint\" title=\"David Anson's VSCode Markdown linter\">linting<\/a>.<\/p>\n<h2 id=\"why-learning-markdown-is-important\">Why learning Markdown is important<\/h2>\n<p>It is the <strong>first thing<\/strong> people see in any Github-hosted project, in the form of a <code>README.md<\/code>. Almost all developer documentation that will ever be written will be done in Markdown, and if it&rsquo;s not, it really, really should be. The entirety of Microsoft&rsquo;s documentation system is a series of Markdown files hosted on Github.<\/p>\n<p>It can be versioned, diff&rsquo;d between versions, is easy to update from anywhere, using everything from <code>vim<\/code> to <code>nano<\/code> to Visual Studio Code to Sublime to Notepad. If JSON is the language of APIS, and YAML the language of configuration, then Markdown is the language of documentation for developers.<\/p>\n<h2 id=\"why-i--markdown\">Why I \ud83d\udc97 Markdown<\/h2>\n<p>I find great joy and beauty in tools paired down to their simplest form, at an abstraction level that&rsquo;s not condescending, that&rsquo;s internally consistent while remaining highly compossible.<\/p>\n<h3 id=\"spend-more-time-editing-less-time-formatting\">Spend more time editing, less time formatting<\/h3>\n<p>Most online rich-text\/HTML editors inject massive amounts of garbage HTML, which I take personally. To the point where I&rsquo;ll spend hours cleaning up rarely referenced online wiki pages that were composed with an HTML editor. Sharepoint and Google Wiki I&rsquo;m looking at you.<\/p>\n<h2 id=\"a-tour-via-tips\">A Tour via Tips<\/h2>\n<h3 id=\"format-w-intent\">Format w\/ intent<\/h3>\n<p>One of my coding principles is never to break your user&rsquo;s trust with UX inconsistencies. I picked this up from the Windows Phone Design Studio, which always stuck with me. Feature adoption drops significantly when a feature isn&rsquo;t consistent.<\/p>\n<p>When a user can&rsquo;t predict when and where a feature will work, they&rsquo;ll start doubting it (<em>&ldquo;What did I do wrong? It worked over there&rdquo;<\/em>) and then avoiding it (<em>&ldquo;I don&rsquo;t know how to use that feature, and that makes me feel dumb, so I&rsquo;ll just avoid it&rdquo;<\/em>).<\/p>\n<ul>\n<li>pick a formatting style and stick with it\n<ul>\n<li>just as with code, consistency, even if you hate it, makes refactoring a sane option<\/li>\n<li>pay special attention to inline code references, such as <code>CosmosDbFailover<\/code> and make sure all code references are formatted the same otherwise, cognitive pattern matching goes out the window<\/li>\n<\/ul>\n<\/li>\n<li>common drift areas to watch for\n<ul>\n<li>mixing bullet style (either <code>*<\/code> or <code>-<\/code> but pick one, <code>*<\/code> is more &ldquo;standard&rdquo;)<\/li>\n<li>forgetting the space between a heading hash and the first character, such as <code>#Title<\/code> compared to the correct <code># Title<\/code><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h3 id=\"work-with-the-constraints\">Work with the constraints<\/h3>\n<ul>\n<li>trust in the content, not the formatting<\/li>\n<li>simplify the design instead of hacking around Markdown<\/li>\n<li>there is rarely a need to mix HTML elements in w\/ Markdown<\/li>\n<li>layout the document knowing it&rsquo;ll be read in plain text as much as rendered HTML<\/li>\n<li>write for the content, not the render. If you can&rsquo;t make sense of the text until it&rsquo;s been rendered, then the problem is probably with the content structure<\/li>\n<\/ul>\n<h3 id=\"using-headings-like-book-titles-and-chapters\">Using headings like book titles and chapters<\/h3>\n<p>A common issue is mixing headings with bold text and swapping them back and forth willy-nilly. In Markdown, a single pound\/hash symbol (<code>#<\/code>) is the same as an H1 in HTML or the same as a book title. A double pound\/hash (<code>##<\/code>) maps to an H2, which roughly maps to chapter titles in a book.<\/p>\n<p>This is a rough analogy, but it&rsquo;s helpful when structuring content to be reminded that a book should only have a single title or a web page should only have a single H1. All my semantic web developers probably have this drilled into their brains. Instead of viewing a # or H1 as a big, bolded font, it&rsquo;s better to view it as the main topic, book, title, blog post title, etc., and according to semantic HTML, a page should only ever have a single H1.<\/p>\n<ul>\n<li>headings (H1, H2, H3, etc.) are often used to render a table of contents (TOC)<\/li>\n<li>view heading levels as an organizational feature instead of formatting<\/li>\n<li>it&rsquo;s okay to break the Highlander rule that there can only be one H1 when there is intent behind it<\/li>\n<\/ul>\n<h3 id=\"when-stuck-take-inspiration-from-others\">When stuck, take inspiration from others<\/h3>\n<ul>\n<li>it&rsquo;s common to know a layout isn&rsquo;t working well but not know why<\/li>\n<li>instead of adding more bold\/italic\/block quotes, look for similar examples<\/li>\n<li>Github is a great go-to for inspiration<\/li>\n<\/ul>\n<h3 id=\"avoid-too-many-call-outs\">Avoid too many call-outs<\/h3>\n<p>Call-outs in this context are those eyeball-grabbing points of interest in the form of a bolded IMPORTANT, a block-quoted pro-tip, or a helpful hint. Used sparingly, they hold the line remarkably well. Add too many, though, and the message gets lost from the constant context switching. If everything is important, then suddenly nothing is important.<\/p>\n<p>If more than &ldquo;some percentage&rdquo; of a document is call-outs, the issue is often one of mixing tones or intent, such as shifting between exposition, extemporization, and detailed steps. The shift back and forth becomes a siren song for call-outs.<\/p>\n<p>Depending on the intent, it&rsquo;s better to pick a single tone or group similar tones together.<\/p>\n<p>For install steps, it&rsquo;s important to keep everything concise and the chatter to a minimum. Reducing each step to basics gives the impression that everything in the list is critical without having to tag every other step with a call-out.<\/p>\n<h3 id=\"code\">Code<\/h3>\n<p>Representing code in Markdown has little overhead and helps so much when reading large articles that it&rsquo;s one of the first things I teach people.<\/p>\n<h4 id=\"code-blocks\">Code Blocks<\/h4>\n<p>Use triple ticks (```) to demarcate multi-line code blocks.<\/p>\n<p><strong>Raw<\/strong><\/p>\n<p>\n```<br\/>\n{<br\/>\n\"userId\": \"1234-ABCD-9876-DCBA\"<br\/>\n}<br\/>\n```<br\/>\n<\/p>\n<p><strong>Rendered<\/strong><\/p>\n<pre tabindex=\"0\"><code>{\n&#34;userId&#34;: &#34;1234-ABCD-9876-DCBA&#34;\n}\n<\/code><\/pre><p>Tell Markdown what language to use for syntax highlighting by adding the language name after the triple ticks, so for JSON it would be <code>```json<\/code>.<\/p>\n<p><strong>Raw<\/strong><\/p>\n<p>\n```json<br\/>\n{<br\/>\n\"userId\": \"1234-ABCD-9876-DCBA\"<br\/>\n}<br\/>\n```<br\/>\n<\/p>\n<p><strong>Rendered<\/strong><\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><span class=\"lnt\">2\n<\/span><span class=\"lnt\">3\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-json\" data-lang=\"json\"><span class=\"line\"><span class=\"cl\"><span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&#34;userId&#34;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&#34;1234-ABCD-9876-DCBA&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><h4 id=\"inline-code-references\">Inline Code References<\/h4>\n<p>Surround text with single ticks (`) to create an inline code reference.<\/p>\n<ul>\n<li>code can be inline, such as &ldquo;class <code>Zuul<\/code> has a dependency on <code>GateKeeper<\/code>&rdquo;.<\/li>\n<li>even minimal syntax highlighting makes a huge difference<\/li>\n<\/ul>\n<h3 id=\"general\">General<\/h3>\n<p>Tips that didn&rsquo;t play well with the other groups, but I think are important.<\/p>\n<ul>\n<li>Use emoji, but with intent and with purpose<\/li>\n<li>Don&rsquo;t be scared of white-space\n<ul>\n<li>space between hash and text<\/li>\n<li>CRLF between headers<\/li>\n<\/ul>\n<\/li>\n<li>Think in terms of outline\/TOC<\/li>\n<li>Use citation references for link-heavy documents<\/li>\n<li>Don&rsquo;t worry about ordered list numbering<\/li>\n<li>Take the extra minute to do look up how to do something<\/li>\n<\/ul>\n<h2 id=\"useful-links\">Useful Links<\/h2>\n<p>Links to things mentioned or hinted.<\/p>\n<ul>\n<li><a href=\"https:\/\/daringfireball.net\/projects\/markdown\/\" title=\"Daring Fireball\">Daring Fireball - Markdown Reference<\/a> - the official site<\/li>\n<li><a href=\"https:\/\/daringfireball.net\/projects\/markdown\/dingus\" title=\"Dingus\">Daring Fireball - Dingus<\/a> - an online Markdown playground<\/li>\n<li><a href=\"https:\/\/github.com\/DavidAnson\/vscode-markdownlint\" title=\"David Anson's VSCode Markdown linter\">David Anson&rsquo;s Markdown Linter for VSCode<\/a> - a great linter to help write better Markdown<\/li>\n<li><a href=\"https:\/\/gohugo.io\/\" title=\"Hugo\">Hugo Open-Source Static Site Generator<\/a> - Markdown-based static site generator<\/li>\n<li><a href=\"https:\/\/jekyllrb.com\/\" title=\"Jekyell Static Site Generator\">Jekyell Static Site Generator<\/a> - another Markdown-based static site generator<\/li>\n<\/ul>","category":[{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/categories\/code\/","term":"Code","label":"Code"}},{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/tags\/markdown\/","term":"Markdown","label":"Markdown"}},{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/tags\/best-practices\/","term":"Best Practices","label":"Best Practices"}}]},{"title":"New Computer Setup Checklist","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/new-computer-setup-checklist\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/new-computer-setup-checklist\/","updated":"2025-07-23T00:00:00+00:00","published":"2022-04-10T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"New Computer Setup Checklist The tools and customizations I like across all my machines in one handy place.\nWindows Apps are listed in the order I prefer to install them, starting right up front with my password manager to make everything else easier.","content":"<h1 id=\"new-computer-setup-checklist\">New Computer Setup Checklist<\/h1>\n<p>The tools and customizations I like across all my machines in one handy place.<\/p>\n<h2 id=\"windows\">Windows<\/h2>\n<p>Apps are listed in the order I prefer to install them, starting right up front with my password manager to make everything else easier.<\/p>\n<h3 id=\"general-utilities\">General Utilities<\/h3>\n<ul>\n<li><a href=\"https:\/\/1password.com\/downloads\/windows\/\">1Password<\/a><\/li>\n<li><a href=\"https:\/\/developer.1password.com\/docs\/cli\/get-started\">1Password CLI<\/a><\/li>\n<li><a href=\"https:\/\/www.voidtools.com\/\">Everything<\/a> (needed for Wox)<\/li>\n<li><a href=\"https:\/\/www.python.org\/downloads\/\">Python 3<\/a> (needed for Wox)<\/li>\n<li><a href=\"https:\/\/github.com\/Wox-launcher\/Wox\/releases\">Wox Launcher<\/a><\/li>\n<\/ul>\n<h3 id=\"editors\">Editors<\/h3>\n<ul>\n<li><a href=\"https:\/\/code.visualstudio.com\/\">Visual Studio Code<\/a> (makes editing profile easier via <code>code $PROFILE<\/code>)<\/li>\n<li><a href=\"https:\/\/www.nerdfonts.com\/font-downloads\">Caskaydia Cove Nerd Font<\/a> (needed for Oh My Posh)<\/li>\n<\/ul>\n<pre tabindex=\"0\"><code># Nerd Fonts, call after installing Oh My Posh\noh-my-posh font install\n<\/code><\/pre><h3 id=\"cli\">CLI<\/h3>\n<ul>\n<li><a href=\"https:\/\/docs.microsoft.com\/en-us\/powershell\/scripting\/install\/installing-powershell-on-windows?view=powershell-7.2\">Latest PowerShell<\/a><\/li>\n<li><a href=\"https:\/\/www.microsoft.com\/en-US\/p\/windows-terminal\/9n0dx20hk701?activetab=pivot:overviewtab\">Windows Terminal<\/a> (if not already installed)<\/li>\n<li><a href=\"https:\/\/docs.microsoft.com\/en-us\/windows\/package-manager\/winget\/\">winget<\/a> (if not already installed)<\/li>\n<li><a href=\"https:\/\/ohmyposh.dev\/\">Oh My Posh<\/a><\/li>\n<li><a href=\"https:\/\/stedolan.github.io\/jq\/download\/\">jq<\/a><\/li>\n<li><a href=\"https:\/\/httpie.io\/\">httpie<\/a><\/li>\n<li><a href=\"https:\/\/git-scm.com\/download\/win\">git<\/a><\/li>\n<li><a href=\"https:\/\/volta.sh\/\">volta<\/a><\/li>\n<\/ul>\n<h3 id=\"wsl\">WSL<\/h3>\n<p>Default Ubuntu, from a PowerShell terminal prompt:<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-powershell\" data-lang=\"powershell\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">wsl<\/span> <span class=\"p\">-<\/span><span class=\"n\">-install<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><h2 id=\"winget-installs\">Winget Installs<\/h2>\n<p>Tools installable via <code>winget<\/code><\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><span class=\"lnt\">2\n<\/span><span class=\"lnt\">3\n<\/span><span class=\"lnt\">4\n<\/span><span class=\"lnt\">5\n<\/span><span class=\"lnt\">6\n<\/span><span class=\"lnt\">7\n<\/span><span class=\"lnt\">8\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-powershell\" data-lang=\"powershell\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">winget<\/span> <span class=\"n\">install<\/span> <span class=\"n\">JanDeDobbeleer<\/span><span class=\"p\">.<\/span><span class=\"py\">OhMyPosh<\/span> <span class=\"n\">-s<\/span> <span class=\"n\">winget<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"n\">winget<\/span> <span class=\"n\">install<\/span> <span class=\"n\">jqlang<\/span><span class=\"p\">.<\/span><span class=\"py\">jq<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"n\">winget<\/span> <span class=\"n\">install<\/span> <span class=\"n\">Git<\/span><span class=\"p\">.<\/span><span class=\"py\">Git<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"n\">winget<\/span> <span class=\"n\">install<\/span> <span class=\"n\">1password-cli<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"n\">winget<\/span> <span class=\"n\">install<\/span> <span class=\"n\">Microsoft<\/span><span class=\"p\">.<\/span><span class=\"py\">PowerToys<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"n\">winget<\/span> <span class=\"n\">install<\/span> <span class=\"n\">voidtools<\/span><span class=\"p\">.<\/span><span class=\"py\">Everything<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"n\">winget<\/span> <span class=\"n\">install<\/span> <span class=\"n\">Wox<\/span><span class=\"p\">.<\/span><span class=\"py\">Wox<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"n\">winget<\/span> <span class=\"n\">install<\/span> <span class=\"n\">Volta<\/span><span class=\"p\">.<\/span><span class=\"py\">Volta<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><h2 id=\"configurations\">Configurations<\/h2>\n<h3 id=\"environment-variables\">Environment Variables<\/h3>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-powershell\" data-lang=\"powershell\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">SOURCE_ROOT<\/span><span class=\"p\">=<\/span><span class=\"n\">C:<\/span><span class=\"p\">\\<\/span><span class=\"n\">Users<\/span><span class=\"p\">\\<\/span><span class=\"n\">monoc<\/span><span class=\"p\">\\<\/span><span class=\"n\">Dropbox<\/span><span class=\"p\">\\<\/span><span class=\"n\">source<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><h3 id=\"git-configuration\">Git Configuration<\/h3>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><span class=\"lnt\">2\n<\/span><span class=\"lnt\">3\n<\/span><span class=\"lnt\">4\n<\/span><span class=\"lnt\">5\n<\/span><span class=\"lnt\">6\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-powershell\" data-lang=\"powershell\"><span class=\"line\"><span class=\"cl\"><span class=\"c\"># set default main branch to `main`<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"n\">git<\/span> <span class=\"n\">config<\/span> <span class=\"p\">-<\/span><span class=\"n\">-global<\/span> <span class=\"n\">init<\/span><span class=\"p\">.<\/span><span class=\"py\">defaultBranch<\/span> <span class=\"n\">main<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\"># Set user information<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"n\">git<\/span> <span class=\"n\">config<\/span> <span class=\"p\">-<\/span><span class=\"n\">-global<\/span> <span class=\"n\">user<\/span><span class=\"p\">.<\/span><span class=\"py\">name<\/span> <span class=\"s2\">&#34;Shawn Oster&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"n\">git<\/span> <span class=\"n\">config<\/span> <span class=\"p\">-<\/span><span class=\"n\">-global<\/span> <span class=\"n\">user<\/span><span class=\"p\">.<\/span><span class=\"py\">email<\/span> <span class=\"s2\">&#34;shawn.oster@gmail.com&#34;<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><h3 id=\"visual-studio-code\">Visual Studio Code<\/h3>\n<h4 id=\"extensions\">Extensions<\/h4>\n<ul>\n<li><a href=\"https:\/\/marketplace.visualstudio.com\/items?itemName=GitHub.remotehub\">GitHub Repositories<\/a> - <em>Remotely browse and edit any GitHub repository<\/em><\/li>\n<li><a href=\"https:\/\/marketplace.visualstudio.com\/items?itemName=mechatroner.rainbow-csv\">Rainbow CSV<\/a> - <em>Highlight CSV and TSV files, Run SQL-like queries<\/em><\/li>\n<li><a href=\"https:\/\/marketplace.visualstudio.com\/items?itemName=ms-vscode.remote-repositories\">Remote Repositories<\/a> - <em>Remotely browse and edit git repositories<\/em><\/li>\n<\/ul>\n<h4 id=\"themes\">Themes<\/h4>\n<ul>\n<li><a href=\"https:\/\/marketplace.visualstudio.com\/items?itemName=narenranjit.chandrian\">Chandrian<\/a> - <em>a semantic syntax highlighting theme<\/em><\/li>\n<\/ul>\n<h3 id=\"wox-configuration\">Wox Configuration<\/h3>\n<ul>\n<li>Theme | BlurBlack<\/li>\n<li>Plugin | Web Search | Change <code>duckduckgo<\/code> to <code>d<\/code> for faster typing<\/li>\n<\/ul>\n<h3 id=\"powershell-profile\">PowerShell Profile<\/h3>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\"> 1\n<\/span><span class=\"lnt\"> 2\n<\/span><span class=\"lnt\"> 3\n<\/span><span class=\"lnt\"> 4\n<\/span><span class=\"lnt\"> 5\n<\/span><span class=\"lnt\"> 6\n<\/span><span class=\"lnt\"> 7\n<\/span><span class=\"lnt\"> 8\n<\/span><span class=\"lnt\"> 9\n<\/span><span class=\"lnt\"> 10\n<\/span><span class=\"lnt\"> 11\n<\/span><span class=\"lnt\"> 12\n<\/span><span class=\"lnt\"> 13\n<\/span><span class=\"lnt\"> 14\n<\/span><span class=\"lnt\"> 15\n<\/span><span class=\"lnt\"> 16\n<\/span><span class=\"lnt\"> 17\n<\/span><span class=\"lnt\"> 18\n<\/span><span class=\"lnt\"> 19\n<\/span><span class=\"lnt\"> 20\n<\/span><span class=\"lnt\"> 21\n<\/span><span class=\"lnt\"> 22\n<\/span><span class=\"lnt\"> 23\n<\/span><span class=\"lnt\"> 24\n<\/span><span class=\"lnt\"> 25\n<\/span><span class=\"lnt\"> 26\n<\/span><span class=\"lnt\"> 27\n<\/span><span class=\"lnt\"> 28\n<\/span><span class=\"lnt\"> 29\n<\/span><span class=\"lnt\"> 30\n<\/span><span class=\"lnt\"> 31\n<\/span><span class=\"lnt\"> 32\n<\/span><span class=\"lnt\"> 33\n<\/span><span class=\"lnt\"> 34\n<\/span><span class=\"lnt\"> 35\n<\/span><span class=\"lnt\"> 36\n<\/span><span class=\"lnt\"> 37\n<\/span><span class=\"lnt\"> 38\n<\/span><span class=\"lnt\"> 39\n<\/span><span class=\"lnt\"> 40\n<\/span><span class=\"lnt\"> 41\n<\/span><span class=\"lnt\"> 42\n<\/span><span class=\"lnt\"> 43\n<\/span><span class=\"lnt\"> 44\n<\/span><span class=\"lnt\"> 45\n<\/span><span class=\"lnt\"> 46\n<\/span><span class=\"lnt\"> 47\n<\/span><span class=\"lnt\"> 48\n<\/span><span class=\"lnt\"> 49\n<\/span><span class=\"lnt\"> 50\n<\/span><span class=\"lnt\"> 51\n<\/span><span class=\"lnt\"> 52\n<\/span><span class=\"lnt\"> 53\n<\/span><span class=\"lnt\"> 54\n<\/span><span class=\"lnt\"> 55\n<\/span><span class=\"lnt\"> 56\n<\/span><span class=\"lnt\"> 57\n<\/span><span class=\"lnt\"> 58\n<\/span><span class=\"lnt\"> 59\n<\/span><span class=\"lnt\"> 60\n<\/span><span class=\"lnt\"> 61\n<\/span><span class=\"lnt\"> 62\n<\/span><span class=\"lnt\"> 63\n<\/span><span class=\"lnt\"> 64\n<\/span><span class=\"lnt\"> 65\n<\/span><span class=\"lnt\"> 66\n<\/span><span class=\"lnt\"> 67\n<\/span><span class=\"lnt\"> 68\n<\/span><span class=\"lnt\"> 69\n<\/span><span class=\"lnt\"> 70\n<\/span><span class=\"lnt\"> 71\n<\/span><span class=\"lnt\"> 72\n<\/span><span class=\"lnt\"> 73\n<\/span><span class=\"lnt\"> 74\n<\/span><span class=\"lnt\"> 75\n<\/span><span class=\"lnt\"> 76\n<\/span><span class=\"lnt\"> 77\n<\/span><span class=\"lnt\"> 78\n<\/span><span class=\"lnt\"> 79\n<\/span><span class=\"lnt\"> 80\n<\/span><span class=\"lnt\"> 81\n<\/span><span class=\"lnt\"> 82\n<\/span><span class=\"lnt\"> 83\n<\/span><span class=\"lnt\"> 84\n<\/span><span class=\"lnt\"> 85\n<\/span><span class=\"lnt\"> 86\n<\/span><span class=\"lnt\"> 87\n<\/span><span class=\"lnt\"> 88\n<\/span><span class=\"lnt\"> 89\n<\/span><span class=\"lnt\"> 90\n<\/span><span class=\"lnt\"> 91\n<\/span><span class=\"lnt\"> 92\n<\/span><span class=\"lnt\"> 93\n<\/span><span class=\"lnt\"> 94\n<\/span><span class=\"lnt\"> 95\n<\/span><span class=\"lnt\"> 96\n<\/span><span class=\"lnt\"> 97\n<\/span><span class=\"lnt\"> 98\n<\/span><span class=\"lnt\"> 99\n<\/span><span class=\"lnt\">100\n<\/span><span class=\"lnt\">101\n<\/span><span class=\"lnt\">102\n<\/span><span class=\"lnt\">103\n<\/span><span class=\"lnt\">104\n<\/span><span class=\"lnt\">105\n<\/span><span class=\"lnt\">106\n<\/span><span class=\"lnt\">107\n<\/span><span class=\"lnt\">108\n<\/span><span class=\"lnt\">109\n<\/span><span class=\"lnt\">110\n<\/span><span class=\"lnt\">111\n<\/span><span class=\"lnt\">112\n<\/span><span class=\"lnt\">113\n<\/span><span class=\"lnt\">114\n<\/span><span class=\"lnt\">115\n<\/span><span class=\"lnt\">116\n<\/span><span class=\"lnt\">117\n<\/span><span class=\"lnt\">118\n<\/span><span class=\"lnt\">119\n<\/span><span class=\"lnt\">120\n<\/span><span class=\"lnt\">121\n<\/span><span class=\"lnt\">122\n<\/span><span class=\"lnt\">123\n<\/span><span class=\"lnt\">124\n<\/span><span class=\"lnt\">125\n<\/span><span class=\"lnt\">126\n<\/span><span class=\"lnt\">127\n<\/span><span class=\"lnt\">128\n<\/span><span class=\"lnt\">129\n<\/span><span class=\"lnt\">130\n<\/span><span class=\"lnt\">131\n<\/span><span class=\"lnt\">132\n<\/span><span class=\"lnt\">133\n<\/span><span class=\"lnt\">134\n<\/span><span class=\"lnt\">135\n<\/span><span class=\"lnt\">136\n<\/span><span class=\"lnt\">137\n<\/span><span class=\"lnt\">138\n<\/span><span class=\"lnt\">139\n<\/span><span class=\"lnt\">140\n<\/span><span class=\"lnt\">141\n<\/span><span class=\"lnt\">142\n<\/span><span class=\"lnt\">143\n<\/span><span class=\"lnt\">144\n<\/span><span class=\"lnt\">145\n<\/span><span class=\"lnt\">146\n<\/span><span class=\"lnt\">147\n<\/span><span class=\"lnt\">148\n<\/span><span class=\"lnt\">149\n<\/span><span class=\"lnt\">150\n<\/span><span class=\"lnt\">151\n<\/span><span class=\"lnt\">152\n<\/span><span class=\"lnt\">153\n<\/span><span class=\"lnt\">154\n<\/span><span class=\"lnt\">155\n<\/span><span class=\"lnt\">156\n<\/span><span class=\"lnt\">157\n<\/span><span class=\"lnt\">158\n<\/span><span class=\"lnt\">159\n<\/span><span class=\"lnt\">160\n<\/span><span class=\"lnt\">161\n<\/span><span class=\"lnt\">162\n<\/span><span class=\"lnt\">163\n<\/span><span class=\"lnt\">164\n<\/span><span class=\"lnt\">165\n<\/span><span class=\"lnt\">166\n<\/span><span class=\"lnt\">167\n<\/span><span class=\"lnt\">168\n<\/span><span class=\"lnt\">169\n<\/span><span class=\"lnt\">170\n<\/span><span class=\"lnt\">171\n<\/span><span class=\"lnt\">172\n<\/span><span class=\"lnt\">173\n<\/span><span class=\"lnt\">174\n<\/span><span class=\"lnt\">175\n<\/span><span class=\"lnt\">176\n<\/span><span class=\"lnt\">177\n<\/span><span class=\"lnt\">178\n<\/span><span class=\"lnt\">179\n<\/span><span class=\"lnt\">180\n<\/span><span class=\"lnt\">181\n<\/span><span class=\"lnt\">182\n<\/span><span class=\"lnt\">183\n<\/span><span class=\"lnt\">184\n<\/span><span class=\"lnt\">185\n<\/span><span class=\"lnt\">186\n<\/span><span class=\"lnt\">187\n<\/span><span class=\"lnt\">188\n<\/span><span class=\"lnt\">189\n<\/span><span class=\"lnt\">190\n<\/span><span class=\"lnt\">191\n<\/span><span class=\"lnt\">192\n<\/span><span class=\"lnt\">193\n<\/span><span class=\"lnt\">194\n<\/span><span class=\"lnt\">195\n<\/span><span class=\"lnt\">196\n<\/span><span class=\"lnt\">197\n<\/span><span class=\"lnt\">198\n<\/span><span class=\"lnt\">199\n<\/span><span class=\"lnt\">200\n<\/span><span class=\"lnt\">201\n<\/span><span class=\"lnt\">202\n<\/span><span class=\"lnt\">203\n<\/span><span class=\"lnt\">204\n<\/span><span class=\"lnt\">205\n<\/span><span class=\"lnt\">206\n<\/span><span class=\"lnt\">207\n<\/span><span class=\"lnt\">208\n<\/span><span class=\"lnt\">209\n<\/span><span class=\"lnt\">210\n<\/span><span class=\"lnt\">211\n<\/span><span class=\"lnt\">212\n<\/span><span class=\"lnt\">213\n<\/span><span class=\"lnt\">214\n<\/span><span class=\"lnt\">215\n<\/span><span class=\"lnt\">216\n<\/span><span class=\"lnt\">217\n<\/span><span class=\"lnt\">218\n<\/span><span class=\"lnt\">219\n<\/span><span class=\"lnt\">220\n<\/span><span class=\"lnt\">221\n<\/span><span class=\"lnt\">222\n<\/span><span class=\"lnt\">223\n<\/span><span class=\"lnt\">224\n<\/span><span class=\"lnt\">225\n<\/span><span class=\"lnt\">226\n<\/span><span class=\"lnt\">227\n<\/span><span class=\"lnt\">228\n<\/span><span class=\"lnt\">229\n<\/span><span class=\"lnt\">230\n<\/span><span class=\"lnt\">231\n<\/span><span class=\"lnt\">232\n<\/span><span class=\"lnt\">233\n<\/span><span class=\"lnt\">234\n<\/span><span class=\"lnt\">235\n<\/span><span class=\"lnt\">236\n<\/span><span class=\"lnt\">237\n<\/span><span class=\"lnt\">238\n<\/span><span class=\"lnt\">239\n<\/span><span class=\"lnt\">240\n<\/span><span class=\"lnt\">241\n<\/span><span class=\"lnt\">242\n<\/span><span class=\"lnt\">243\n<\/span><span class=\"lnt\">244\n<\/span><span class=\"lnt\">245\n<\/span><span class=\"lnt\">246\n<\/span><span class=\"lnt\">247\n<\/span><span class=\"lnt\">248\n<\/span><span class=\"lnt\">249\n<\/span><span class=\"lnt\">250\n<\/span><span class=\"lnt\">251\n<\/span><span class=\"lnt\">252\n<\/span><span class=\"lnt\">253\n<\/span><span class=\"lnt\">254\n<\/span><span class=\"lnt\">255\n<\/span><span class=\"lnt\">256\n<\/span><span class=\"lnt\">257\n<\/span><span class=\"lnt\">258\n<\/span><span class=\"lnt\">259\n<\/span><span class=\"lnt\">260\n<\/span><span class=\"lnt\">261\n<\/span><span class=\"lnt\">262\n<\/span><span class=\"lnt\">263\n<\/span><span class=\"lnt\">264\n<\/span><span class=\"lnt\">265\n<\/span><span class=\"lnt\">266\n<\/span><span class=\"lnt\">267\n<\/span><span class=\"lnt\">268\n<\/span><span class=\"lnt\">269\n<\/span><span class=\"lnt\">270\n<\/span><span class=\"lnt\">271\n<\/span><span class=\"lnt\">272\n<\/span><span class=\"lnt\">273\n<\/span><span class=\"lnt\">274\n<\/span><span class=\"lnt\">275\n<\/span><span class=\"lnt\">276\n<\/span><span class=\"lnt\">277\n<\/span><span class=\"lnt\">278\n<\/span><span class=\"lnt\">279\n<\/span><span class=\"lnt\">280\n<\/span><span class=\"lnt\">281\n<\/span><span class=\"lnt\">282\n<\/span><span class=\"lnt\">283\n<\/span><span class=\"lnt\">284\n<\/span><span class=\"lnt\">285\n<\/span><span class=\"lnt\">286\n<\/span><span class=\"lnt\">287\n<\/span><span class=\"lnt\">288\n<\/span><span class=\"lnt\">289\n<\/span><span class=\"lnt\">290\n<\/span><span class=\"lnt\">291\n<\/span><span class=\"lnt\">292\n<\/span><span class=\"lnt\">293\n<\/span><span class=\"lnt\">294\n<\/span><span class=\"lnt\">295\n<\/span><span class=\"lnt\">296\n<\/span><span class=\"lnt\">297\n<\/span><span class=\"lnt\">298\n<\/span><span class=\"lnt\">299\n<\/span><span class=\"lnt\">300\n<\/span><span class=\"lnt\">301\n<\/span><span class=\"lnt\">302\n<\/span><span class=\"lnt\">303\n<\/span><span class=\"lnt\">304\n<\/span><span class=\"lnt\">305\n<\/span><span class=\"lnt\">306\n<\/span><span class=\"lnt\">307\n<\/span><span class=\"lnt\">308\n<\/span><span class=\"lnt\">309\n<\/span><span class=\"lnt\">310\n<\/span><span class=\"lnt\">311\n<\/span><span class=\"lnt\">312\n<\/span><span class=\"lnt\">313\n<\/span><span class=\"lnt\">314\n<\/span><span class=\"lnt\">315\n<\/span><span class=\"lnt\">316\n<\/span><span class=\"lnt\">317\n<\/span><span class=\"lnt\">318\n<\/span><span class=\"lnt\">319\n<\/span><span class=\"lnt\">320\n<\/span><span class=\"lnt\">321\n<\/span><span class=\"lnt\">322\n<\/span><span class=\"lnt\">323\n<\/span><span class=\"lnt\">324\n<\/span><span class=\"lnt\">325\n<\/span><span class=\"lnt\">326\n<\/span><span class=\"lnt\">327\n<\/span><span class=\"lnt\">328\n<\/span><span class=\"lnt\">329\n<\/span><span class=\"lnt\">330\n<\/span><span class=\"lnt\">331\n<\/span><span class=\"lnt\">332\n<\/span><span class=\"lnt\">333\n<\/span><span class=\"lnt\">334\n<\/span><span class=\"lnt\">335\n<\/span><span class=\"lnt\">336\n<\/span><span class=\"lnt\">337\n<\/span><span class=\"lnt\">338\n<\/span><span class=\"lnt\">339\n<\/span><span class=\"lnt\">340\n<\/span><span class=\"lnt\">341\n<\/span><span class=\"lnt\">342\n<\/span><span class=\"lnt\">343\n<\/span><span class=\"lnt\">344\n<\/span><span class=\"lnt\">345\n<\/span><span class=\"lnt\">346\n<\/span><span class=\"lnt\">347\n<\/span><span class=\"lnt\">348\n<\/span><span class=\"lnt\">349\n<\/span><span class=\"lnt\">350\n<\/span><span class=\"lnt\">351\n<\/span><span class=\"lnt\">352\n<\/span><span class=\"lnt\">353\n<\/span><span class=\"lnt\">354\n<\/span><span class=\"lnt\">355\n<\/span><span class=\"lnt\">356\n<\/span><span class=\"lnt\">357\n<\/span><span class=\"lnt\">358\n<\/span><span class=\"lnt\">359\n<\/span><span class=\"lnt\">360\n<\/span><span class=\"lnt\">361\n<\/span><span class=\"lnt\">362\n<\/span><span class=\"lnt\">363\n<\/span><span class=\"lnt\">364\n<\/span><span class=\"lnt\">365\n<\/span><span class=\"lnt\">366\n<\/span><span class=\"lnt\">367\n<\/span><span class=\"lnt\">368\n<\/span><span class=\"lnt\">369\n<\/span><span class=\"lnt\">370\n<\/span><span class=\"lnt\">371\n<\/span><span class=\"lnt\">372\n<\/span><span class=\"lnt\">373\n<\/span><span class=\"lnt\">374\n<\/span><span class=\"lnt\">375\n<\/span><span class=\"lnt\">376\n<\/span><span class=\"lnt\">377\n<\/span><span class=\"lnt\">378\n<\/span><span class=\"lnt\">379\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-powershell\" data-lang=\"powershell\"><span class=\"line\"><span class=\"cl\"><span class=\"c\">#<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\"># Shawn Oster&#39;s PowerShell settings<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\">#<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\"># 1. Open profile settings with `code $PROFILE`<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\"># 2. Paste everything<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\"># 3. Reload shell with `. $PROFILE`<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\">#<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"n\">using<\/span> <span class=\"n\">namespace<\/span> <span class=\"n\">System<\/span><span class=\"p\">.<\/span><span class=\"py\">Management<\/span><span class=\"p\">.<\/span><span class=\"py\">Automation<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"n\">using<\/span> <span class=\"n\">namespace<\/span> <span class=\"n\">System<\/span><span class=\"p\">.<\/span><span class=\"py\">Management<\/span><span class=\"p\">.<\/span><span class=\"py\">Automation<\/span><span class=\"p\">.<\/span><span class=\"py\">Language<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\">#<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\"># Tab-completion<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\">#<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\"># 1Password CLI<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"n\">op<\/span> <span class=\"n\">completion<\/span> <span class=\"n\">powershell<\/span> <span class=\"p\">|<\/span> <span class=\"nb\">Out-String<\/span> <span class=\"p\">|<\/span> <span class=\"nb\">Invoke-Expression<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\"># AWS CLI<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nb\">Register-ArgumentCompleter<\/span> <span class=\"n\">-Native<\/span> <span class=\"n\">-CommandName<\/span> <span class=\"n\">aws<\/span> <span class=\"n\">-ScriptBlock<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">param<\/span><span class=\"p\">(<\/span><span class=\"nv\">$commandName<\/span><span class=\"p\">,<\/span> <span class=\"nv\">$wordToComplete<\/span><span class=\"p\">,<\/span> <span class=\"nv\">$cursorPosition<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nv\">$env:COMP_LINE<\/span> <span class=\"p\">=<\/span> <span class=\"nv\">$wordToComplete<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"nv\">$env:COMP_LINE<\/span><span class=\"p\">.<\/span><span class=\"py\">Length<\/span> <span class=\"o\">-lt<\/span> <span class=\"nv\">$cursorPosition<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nv\">$env:COMP_LINE<\/span> <span class=\"p\">=<\/span> <span class=\"nv\">$env:COMP_LINE<\/span> <span class=\"p\">+<\/span> <span class=\"s2\">&#34; &#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nv\">$env:COMP_POINT<\/span> <span class=\"p\">=<\/span> <span class=\"nv\">$cursorPosition<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">aws_completer<\/span><span class=\"p\">.<\/span><span class=\"py\">exe<\/span> <span class=\"p\">|<\/span> <span class=\"nb\">ForEach-Object<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">System.Management.Automation.CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"nv\">$_<\/span><span class=\"p\">,<\/span> <span class=\"nv\">$_<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;ParameterValue&#39;<\/span><span class=\"p\">,<\/span> <span class=\"nv\">$_<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nb\">Remove-Item<\/span> <span class=\"n\">Env<\/span><span class=\"err\">:<\/span><span class=\"p\">\\<\/span><span class=\"n\">COMP_LINE<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nb\">Remove-Item<\/span> <span class=\"n\">Env<\/span><span class=\"err\">:<\/span><span class=\"p\">\\<\/span><span class=\"n\">COMP_POINT<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\"># dotnet CLI<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\">#<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\"># https:\/\/docs.microsoft.com\/en-us\/dotnet\/core\/tools\/enable-tab-autocomplete<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nb\">Register-ArgumentCompleter<\/span> <span class=\"n\">-Native<\/span> <span class=\"n\">-CommandName<\/span> <span class=\"n\">dotnet<\/span> <span class=\"n\">-ScriptBlock<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">param<\/span><span class=\"p\">(<\/span><span class=\"nv\">$commandName<\/span><span class=\"p\">,<\/span> <span class=\"nv\">$wordToComplete<\/span><span class=\"p\">,<\/span> <span class=\"nv\">$cursorPosition<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">dotnet<\/span> <span class=\"n\">complete<\/span> <span class=\"p\">-<\/span><span class=\"n\">-position<\/span> <span class=\"nv\">$cursorPosition<\/span> <span class=\"s2\">&#34;<\/span><span class=\"nv\">$wordToComplete<\/span><span class=\"s2\">&#34;<\/span> <span class=\"p\">|<\/span> <span class=\"nb\">ForEach-Object<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">System.Management.Automation.CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"nv\">$_<\/span><span class=\"p\">,<\/span> <span class=\"nv\">$_<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;ParameterValue&#39;<\/span><span class=\"p\">,<\/span> <span class=\"nv\">$_<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\"># winget<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nb\">Register-ArgumentCompleter<\/span> <span class=\"n\">-Native<\/span> <span class=\"n\">-CommandName<\/span> <span class=\"n\">winget<\/span> <span class=\"n\">-ScriptBlock<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">param<\/span><span class=\"p\">(<\/span><span class=\"nv\">$wordToComplete<\/span><span class=\"p\">,<\/span> <span class=\"nv\">$commandAst<\/span><span class=\"p\">,<\/span> <span class=\"nv\">$cursorPosition<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">Console<\/span><span class=\"p\">]::<\/span><span class=\"n\">InputEncoding<\/span> <span class=\"p\">=<\/span> <span class=\"p\">[<\/span><span class=\"no\">Console<\/span><span class=\"p\">]::<\/span><span class=\"n\">OutputEncoding<\/span> <span class=\"p\">=<\/span> <span class=\"nv\">$OutputEncoding<\/span> <span class=\"p\">=<\/span> <span class=\"p\">[<\/span><span class=\"no\">System.Text.Utf8Encoding<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">()<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nv\">$Local<\/span><span class=\"err\">:<\/span><span class=\"n\">word<\/span> <span class=\"p\">=<\/span> <span class=\"nv\">$wordToComplete<\/span><span class=\"p\">.<\/span><span class=\"py\">Replace<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;&#34;&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;&#34;&#34;&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nv\">$Local<\/span><span class=\"err\">:<\/span><span class=\"n\">ast<\/span> <span class=\"p\">=<\/span> <span class=\"nv\">$commandAst<\/span><span class=\"p\">.<\/span><span class=\"py\">ToString<\/span><span class=\"p\">().<\/span><span class=\"py\">Replace<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;&#34;&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;&#34;&#34;&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">winget<\/span> <span class=\"n\">complete<\/span> <span class=\"p\">-<\/span><span class=\"n\">-word<\/span><span class=\"p\">=<\/span><span class=\"s2\">&#34;<\/span><span class=\"nv\">$Local<\/span><span class=\"s2\">:word&#34;<\/span> <span class=\"p\">-<\/span><span class=\"n\">-commandline<\/span> <span class=\"s2\">&#34;<\/span><span class=\"nv\">$Local<\/span><span class=\"s2\">:ast&#34;<\/span> <span class=\"p\">-<\/span><span class=\"n\">-position<\/span> <span class=\"nv\">$cursorPosition<\/span> <span class=\"p\">|<\/span> <span class=\"nb\">ForEach-Object<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">System.Management.Automation.CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"nv\">$_<\/span><span class=\"p\">,<\/span> <span class=\"nv\">$_<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;ParameterValue&#39;<\/span><span class=\"p\">,<\/span> <span class=\"nv\">$_<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\"># volta<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\">#<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\"># generate with `volta completions powershell`<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nb\">Register-ArgumentCompleter<\/span> <span class=\"n\">-Native<\/span> <span class=\"n\">-CommandName<\/span> <span class=\"s1\">&#39;volta&#39;<\/span> <span class=\"n\">-ScriptBlock<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">param<\/span><span class=\"p\">(<\/span><span class=\"nv\">$wordToComplete<\/span><span class=\"p\">,<\/span> <span class=\"nv\">$commandAst<\/span><span class=\"p\">,<\/span> <span class=\"nv\">$cursorPosition<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nv\">$commandElements<\/span> <span class=\"p\">=<\/span> <span class=\"nv\">$commandAst<\/span><span class=\"p\">.<\/span><span class=\"py\">CommandElements<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nv\">$command<\/span> <span class=\"p\">=<\/span> <span class=\"vm\">@<\/span><span class=\"p\">(<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"s1\">&#39;volta&#39;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">for<\/span> <span class=\"p\">(<\/span><span class=\"nv\">$i<\/span> <span class=\"p\">=<\/span> <span class=\"mf\">1<\/span><span class=\"p\">;<\/span> <span class=\"nv\">$i<\/span> <span class=\"o\">-lt<\/span> <span class=\"nv\">$commandElements<\/span><span class=\"p\">.<\/span><span class=\"n\">Count<\/span><span class=\"p\">;<\/span> <span class=\"nv\">$i<\/span><span class=\"p\">++)<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nv\">$element<\/span> <span class=\"p\">=<\/span> <span class=\"nv\">$commandElements<\/span><span class=\"p\">[<\/span><span class=\"nv\">$i<\/span><span class=\"p\">]<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"nv\">$element<\/span> <span class=\"o\">-isnot<\/span> <span class=\"p\">[<\/span><span class=\"no\">StringConstantExpressionAst<\/span><span class=\"p\">]<\/span> <span class=\"o\">-or<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nv\">$element<\/span><span class=\"p\">.<\/span><span class=\"py\">StringConstantType<\/span> <span class=\"o\">-ne<\/span> <span class=\"p\">[<\/span><span class=\"no\">StringConstantType<\/span><span class=\"p\">]::<\/span><span class=\"n\">BareWord<\/span> <span class=\"o\">-or<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nv\">$element<\/span><span class=\"p\">.<\/span><span class=\"py\">Value<\/span><span class=\"p\">.<\/span><span class=\"py\">StartsWith<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;-&#39;<\/span><span class=\"p\">)<\/span> <span class=\"o\">-or<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nv\">$element<\/span><span class=\"p\">.<\/span><span class=\"py\">Value<\/span> <span class=\"o\">-eq<\/span> <span class=\"nv\">$wordToComplete<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">break<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nv\">$element<\/span><span class=\"p\">.<\/span><span class=\"py\">Value<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">})<\/span> <span class=\"n\">-join<\/span> <span class=\"s1\">&#39;;&#39;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nv\">$completions<\/span> <span class=\"p\">=<\/span> <span class=\"vm\">@<\/span><span class=\"p\">(<\/span><span class=\"k\">switch<\/span> <span class=\"p\">(<\/span><span class=\"nv\">$command<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"s1\">&#39;volta&#39;<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--verbose&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--verbose&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Enables verbose diagnostics&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--very-verbose&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--very-verbose&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Enables trace-level diagnostics&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--quiet&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--quiet&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Prevents unnecessary output&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;-v&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;-v&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Prints the current version of Volta&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--version&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--version&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Prints the current version of Volta&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;-h&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;-h&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Print help (see more with &#39;&#39;--help&#39;&#39;)&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--help&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--help&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Print help (see more with &#39;&#39;--help&#39;&#39;)&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;fetch&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;fetch&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterValue<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Fetches a tool to the local machine&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;install&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;install&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterValue<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Installs a tool in your toolchain&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;uninstall&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;uninstall&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterValue<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Uninstalls a tool from your toolchain&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;pin&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;pin&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterValue<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Pins your project&#39;&#39;s runtime or package manager&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;list&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;list&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterValue<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Displays the current toolchain&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;completions&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;completions&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterValue<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Generates Volta completions&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;which&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;which&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterValue<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Locates the actual binary that will be called by Volta&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;use&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;use&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterValue<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;use&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;setup&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;setup&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterValue<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Enables Volta for the current user \/ shell&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;run&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;run&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterValue<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Run a command with custom Node, npm, pnpm, and\/or Yarn versions&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;help&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;help&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterValue<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Print this message or the help of the given subcommand(s)&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">break<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"s1\">&#39;volta;fetch&#39;<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--verbose&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--verbose&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Enables verbose diagnostics&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--very-verbose&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--very-verbose&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Enables trace-level diagnostics&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--quiet&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--quiet&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Prevents unnecessary output&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;-h&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;-h&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Print help&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--help&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--help&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Print help&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">break<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"s1\">&#39;volta;install&#39;<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--verbose&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--verbose&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Enables verbose diagnostics&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--very-verbose&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--very-verbose&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Enables trace-level diagnostics&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--quiet&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--quiet&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Prevents unnecessary output&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;-h&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;-h&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Print help&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--help&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--help&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Print help&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">break<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"s1\">&#39;volta;uninstall&#39;<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--verbose&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--verbose&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Enables verbose diagnostics&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--very-verbose&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--very-verbose&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Enables trace-level diagnostics&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--quiet&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--quiet&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Prevents unnecessary output&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;-h&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;-h&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Print help&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--help&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--help&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Print help&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">break<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"s1\">&#39;volta;pin&#39;<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--verbose&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--verbose&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Enables verbose diagnostics&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--very-verbose&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--very-verbose&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Enables trace-level diagnostics&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--quiet&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--quiet&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Prevents unnecessary output&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;-h&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;-h&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Print help&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--help&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--help&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Print help&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">break<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"s1\">&#39;volta;list&#39;<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--format&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--format&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Specify the output format&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;-c&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;-c&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Show the currently-active tool(s)&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--current&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--current&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Show the currently-active tool(s)&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;-d&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;-d&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Show your default tool(s)&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--default&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--default&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Show your default tool(s)&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--verbose&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--verbose&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Enables verbose diagnostics&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--very-verbose&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--very-verbose&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Enables trace-level diagnostics&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--quiet&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--quiet&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Prevents unnecessary output&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;-h&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;-h&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Print help (see more with &#39;&#39;--help&#39;&#39;)&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--help&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--help&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Print help (see more with &#39;&#39;--help&#39;&#39;)&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">break<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"s1\">&#39;volta;completions&#39;<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;-o&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;-o&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;File to write generated completions to&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--output&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--output&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;File to write generated completions to&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;-f&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;-f&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Write over an existing file, if any&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--force&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--force&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Write over an existing file, if any&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--verbose&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--verbose&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Enables verbose diagnostics&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--very-verbose&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--very-verbose&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Enables trace-level diagnostics&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--quiet&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--quiet&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Prevents unnecessary output&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;-h&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;-h&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Print help (see more with &#39;&#39;--help&#39;&#39;)&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--help&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--help&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Print help (see more with &#39;&#39;--help&#39;&#39;)&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">break<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"s1\">&#39;volta;which&#39;<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--verbose&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--verbose&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Enables verbose diagnostics&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--very-verbose&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--very-verbose&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Enables trace-level diagnostics&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--quiet&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--quiet&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Prevents unnecessary output&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;-h&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;-h&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Print help&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--help&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--help&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Print help&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">break<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"s1\">&#39;volta;use&#39;<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--verbose&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--verbose&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Enables verbose diagnostics&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--very-verbose&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--very-verbose&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Enables trace-level diagnostics&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--quiet&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--quiet&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Prevents unnecessary output&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;-h&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;-h&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Print help (see more with &#39;&#39;--help&#39;&#39;)&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--help&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--help&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Print help (see more with &#39;&#39;--help&#39;&#39;)&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">break<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"s1\">&#39;volta;setup&#39;<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--verbose&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--verbose&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Enables verbose diagnostics&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--very-verbose&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--very-verbose&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Enables trace-level diagnostics&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--quiet&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--quiet&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Prevents unnecessary output&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;-h&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;-h&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Print help&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--help&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--help&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Print help&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">break<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"s1\">&#39;volta;run&#39;<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--node&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--node&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Set the custom Node version&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--npm&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--npm&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Set the custom npm version&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--pnpm&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--pnpm&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Set the custon pnpm version&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--yarn&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--yarn&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Set the custom Yarn version&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--env&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--env&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Set an environment variable (can be used multiple times)&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--bundled-npm&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--bundled-npm&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Forces npm to be the version bundled with Node&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--no-pnpm&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--no-pnpm&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Disables pnpm&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--no-yarn&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--no-yarn&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Disables Yarn&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--verbose&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--verbose&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Enables verbose diagnostics&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--very-verbose&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--very-verbose&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Enables trace-level diagnostics&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--quiet&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--quiet&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Prevents unnecessary output&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;-h&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;-h&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Print help&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;--help&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--help&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterName<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Print help&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">break<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"s1\">&#39;volta;help&#39;<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;fetch&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;fetch&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterValue<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Fetches a tool to the local machine&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;install&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;install&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterValue<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Installs a tool in your toolchain&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;uninstall&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;uninstall&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterValue<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Uninstalls a tool from your toolchain&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;pin&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;pin&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterValue<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Pins your project&#39;&#39;s runtime or package manager&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;list&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;list&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterValue<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Displays the current toolchain&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;completions&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;completions&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterValue<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Generates Volta completions&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;which&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;which&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterValue<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Locates the actual binary that will be called by Volta&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;use&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;use&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterValue<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;use&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;setup&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;setup&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterValue<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Enables Volta for the current user \/ shell&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;run&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;run&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterValue<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Run a command with custom Node, npm, pnpm, and\/or Yarn versions&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;help&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;help&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"no\">CompletionResultType<\/span><span class=\"p\">]::<\/span><span class=\"n\">ParameterValue<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Print this message or the help of the given subcommand(s)&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">break<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"s1\">&#39;volta;help;fetch&#39;<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">break<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"s1\">&#39;volta;help;install&#39;<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">break<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"s1\">&#39;volta;help;uninstall&#39;<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">break<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"s1\">&#39;volta;help;pin&#39;<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">break<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"s1\">&#39;volta;help;list&#39;<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">break<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"s1\">&#39;volta;help;completions&#39;<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">break<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"s1\">&#39;volta;help;which&#39;<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">break<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"s1\">&#39;volta;help;use&#39;<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">break<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"s1\">&#39;volta;help;setup&#39;<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">break<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"s1\">&#39;volta;help;run&#39;<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">break<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"s1\">&#39;volta;help;help&#39;<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">break<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">})<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nv\">$completions<\/span><span class=\"p\">.<\/span><span class=\"py\">Where<\/span><span class=\"p\">{<\/span> <span class=\"nv\">$_<\/span><span class=\"p\">.<\/span><span class=\"py\">CompletionText<\/span> <span class=\"o\">-like<\/span> <span class=\"s2\">&#34;<\/span><span class=\"nv\">$wordToComplete<\/span><span class=\"s2\">*&#34;<\/span> <span class=\"p\">}<\/span> <span class=\"p\">|<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nb\">Sort-Object<\/span> <span class=\"n\">-Property<\/span> <span class=\"n\">ListItemText<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\"># winget<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nb\">Register-ArgumentCompleter<\/span> <span class=\"n\">-Native<\/span> <span class=\"n\">-CommandName<\/span> <span class=\"n\">winget<\/span> <span class=\"n\">-ScriptBlock<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">param<\/span><span class=\"p\">(<\/span><span class=\"nv\">$wordToComplete<\/span><span class=\"p\">,<\/span> <span class=\"nv\">$commandAst<\/span><span class=\"p\">,<\/span> <span class=\"nv\">$cursorPosition<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">Console<\/span><span class=\"p\">]::<\/span><span class=\"n\">InputEncoding<\/span> <span class=\"p\">=<\/span> <span class=\"p\">[<\/span><span class=\"no\">Console<\/span><span class=\"p\">]::<\/span><span class=\"n\">OutputEncoding<\/span> <span class=\"p\">=<\/span> <span class=\"nv\">$OutputEncoding<\/span> <span class=\"p\">=<\/span> <span class=\"p\">[<\/span><span class=\"no\">System.Text.Utf8Encoding<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">()<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nv\">$Local<\/span><span class=\"err\">:<\/span><span class=\"n\">word<\/span> <span class=\"p\">=<\/span> <span class=\"nv\">$wordToComplete<\/span><span class=\"p\">.<\/span><span class=\"py\">Replace<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;&#34;&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;&#34;&#34;&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nv\">$Local<\/span><span class=\"err\">:<\/span><span class=\"n\">ast<\/span> <span class=\"p\">=<\/span> <span class=\"nv\">$commandAst<\/span><span class=\"p\">.<\/span><span class=\"py\">ToString<\/span><span class=\"p\">().<\/span><span class=\"py\">Replace<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;&#34;&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;&#34;&#34;&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">winget<\/span> <span class=\"n\">complete<\/span> <span class=\"p\">-<\/span><span class=\"n\">-word<\/span><span class=\"p\">=<\/span><span class=\"s2\">&#34;<\/span><span class=\"nv\">$Local<\/span><span class=\"s2\">:word&#34;<\/span> <span class=\"p\">-<\/span><span class=\"n\">-commandline<\/span> <span class=\"s2\">&#34;<\/span><span class=\"nv\">$Local<\/span><span class=\"s2\">:ast&#34;<\/span> <span class=\"p\">-<\/span><span class=\"n\">-position<\/span> <span class=\"nv\">$cursorPosition<\/span> <span class=\"p\">|<\/span> <span class=\"nb\">ForEach-Object<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">[<\/span><span class=\"no\">System.Management.Automation.CompletionResult<\/span><span class=\"p\">]::<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"nv\">$_<\/span><span class=\"p\">,<\/span> <span class=\"nv\">$_<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;ParameterValue&#39;<\/span><span class=\"p\">,<\/span> <span class=\"nv\">$_<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\">#<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\"># Aliases to common directories<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\">#<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\"># S is for Source<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\"># Root directory for all source code (make sure to set SOURCE_ROOT)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"kd\">function<\/span><span class=\"w\"> <\/span><span class=\"nb\">cds<\/span> <span class=\"p\">{<\/span> <span class=\"nb\">Set-Location<\/span> <span class=\"nv\">$env:SOURCE_ROOT<\/span> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"kd\">function<\/span><span class=\"w\"> <\/span><span class=\"nb\">ss<\/span> <span class=\"p\">{<\/span> <span class=\"nb\">sonar-scanner<\/span><span class=\"p\">.<\/span><span class=\"py\">bat<\/span> <span class=\"n\">-D<\/span><span class=\"s2\">&#34;sonar.projectKey=<\/span><span class=\"p\">$(<\/span><span class=\"nb\">Get-Location<\/span> <span class=\"p\">|<\/span> <span class=\"nb\">Split-Path<\/span> <span class=\"n\">-Leaf<\/span><span class=\"p\">)<\/span><span class=\"s2\">&#34;<\/span> <span class=\"n\">-D<\/span><span class=\"s2\">&#34;sonar.python.version=3&#34;<\/span> <span class=\"n\">-D<\/span><span class=\"s2\">&#34;sonar.sourceEncoding=UTF-8&#34;<\/span> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\">#<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\"># Environment variables<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\">#<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nv\">$Env:SOURCE_ROOT<\/span> <span class=\"p\">=<\/span> <span class=\"n\">E:<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nv\">$Env:UV_CACHE_DIR<\/span> <span class=\"p\">=<\/span> <span class=\"s2\">&#34;E:\\.uv&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\"># 1Password-secured Accounts<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\">#<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\"># IDs are meaningless without the password and thus safe for plaintext<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"kd\">function<\/span><span class=\"w\"> <\/span><span class=\"nb\">Set-SecureEnv<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"c\"># Secure variables, pulled from 1Password<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nv\">$Env:GITHUB_TOKEN<\/span> <span class=\"p\">=<\/span> <span class=\"n\">op<\/span> <span class=\"n\">read<\/span> <span class=\"p\">-<\/span><span class=\"n\">-account<\/span> <span class=\"nb\">guild-education<\/span> <span class=\"s2\">&#34;op:\/\/Employee\/GitHub - Token - SQA local testing\/credential&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nv\">$Env:JF_API_KEY<\/span> <span class=\"p\">=<\/span> <span class=\"n\">op<\/span> <span class=\"n\">read<\/span> <span class=\"p\">-<\/span><span class=\"n\">-account<\/span> <span class=\"nb\">guild-education<\/span> <span class=\"s2\">&#34;op:\/\/Engineering Tools - Prod\/Jellyfish API Token\/credential&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nv\">$Env:JIRA_API_KEY<\/span> <span class=\"p\">=<\/span> <span class=\"n\">op<\/span> <span class=\"n\">read<\/span> <span class=\"p\">-<\/span><span class=\"n\">-account<\/span> <span class=\"nb\">guild-education<\/span> <span class=\"s2\">&#34;op:\/\/Employee\/sa-jinx-cli\/credential&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nv\">$Env:JIRA_API_USER<\/span> <span class=\"p\">=<\/span> <span class=\"n\">op<\/span> <span class=\"n\">read<\/span> <span class=\"p\">-<\/span><span class=\"n\">-account<\/span> <span class=\"nb\">guild-education<\/span> <span class=\"s2\">&#34;op:\/\/Employee\/sa-jinx-cli\/username&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nv\">$Env:JIRA_SERVER_URL<\/span> <span class=\"p\">=<\/span> <span class=\"n\">op<\/span> <span class=\"n\">read<\/span> <span class=\"p\">-<\/span><span class=\"n\">-account<\/span> <span class=\"nb\">guild-education<\/span> <span class=\"s2\">&#34;op:\/\/Employee\/sa-jinx-cli\/server&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nv\">$Env:NPM_TOKEN<\/span> <span class=\"p\">=<\/span> <span class=\"n\">op<\/span> <span class=\"n\">read<\/span> <span class=\"p\">-<\/span><span class=\"n\">-account<\/span> <span class=\"nb\">guild-education<\/span> <span class=\"s2\">&#34;op:\/\/Employee\/npm - token - Local CLI\/credential&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nv\">$Env:PACT_READONLY_PASSWORD<\/span> <span class=\"p\">=<\/span> <span class=\"n\">op<\/span> <span class=\"n\">read<\/span> <span class=\"p\">-<\/span><span class=\"n\">-account<\/span> <span class=\"nb\">guild-education<\/span> <span class=\"s2\">&#34;op:\/\/Engineering Tools - Dev\/Pact Broker - Readonly\/password&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nv\">$Env:SONAR_TOKEN<\/span> <span class=\"p\">=<\/span> <span class=\"n\">op<\/span> <span class=\"n\">read<\/span> <span class=\"p\">-<\/span><span class=\"n\">-account<\/span> <span class=\"nb\">guild-education<\/span> <span class=\"s2\">&#34;op:\/\/Employee\/SonarQube - Docker\/token&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nv\">$Env:DATADOG_API_KEY<\/span> <span class=\"p\">=<\/span> <span class=\"n\">op<\/span> <span class=\"n\">read<\/span> <span class=\"p\">-<\/span><span class=\"n\">-account<\/span> <span class=\"nb\">guild-education<\/span> <span class=\"s2\">&#34;op:\/\/Employee\/Datadog - API Key - Self-Serve Workflow\/credential&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nv\">$Env:DATADOG_APP_KEY<\/span> <span class=\"p\">=<\/span> <span class=\"n\">op<\/span> <span class=\"n\">read<\/span> <span class=\"p\">-<\/span><span class=\"n\">-account<\/span> <span class=\"nb\">guild-education<\/span> <span class=\"s2\">&#34;op:\/\/Employee\/Datadog - App Key - Self-Serve Script\/credential&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"kd\">function<\/span><span class=\"w\"> <\/span><span class=\"nb\">secure-groot<\/span> <span class=\"p\">{<\/span> <span class=\"nb\">Set-Location<\/span> <span class=\"p\">(<\/span><span class=\"nb\">Join-Path<\/span> <span class=\"nv\">$env:SOURCE_ROOT<\/span> <span class=\"n\">groot<\/span><span class=\"p\">);<\/span> <span class=\"n\">op<\/span> <span class=\"n\">run<\/span> <span class=\"p\">-<\/span><span class=\"n\">-account<\/span> <span class=\"n\">my<\/span> <span class=\"p\">-<\/span><span class=\"n\">-env<\/span><span class=\"o\">-file<\/span><span class=\"p\">=.\\<\/span><span class=\"n\">app<\/span><span class=\"p\">.<\/span><span class=\"py\">env<\/span> <span class=\"p\">--<\/span> <span class=\"n\">code<\/span> <span class=\"p\">.<\/span> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"kd\">function<\/span><span class=\"w\"> <\/span><span class=\"nb\">secure-wonka<\/span> <span class=\"p\">{<\/span> <span class=\"nb\">Set-Location<\/span> <span class=\"p\">(<\/span><span class=\"nb\">Join-Path<\/span> <span class=\"nv\">$env:SOURCE_ROOT<\/span> <span class=\"n\">wonka<\/span><span class=\"p\">);<\/span> <span class=\"n\">op<\/span> <span class=\"n\">run<\/span> <span class=\"p\">-<\/span><span class=\"n\">-account<\/span> <span class=\"nb\">guild-education<\/span> <span class=\"p\">-<\/span><span class=\"n\">-env<\/span><span class=\"o\">-file<\/span><span class=\"p\">=.\\<\/span><span class=\"n\">wonka<\/span><span class=\"p\">\\<\/span><span class=\"n\">app<\/span><span class=\"p\">.<\/span><span class=\"py\">env<\/span> <span class=\"p\">--<\/span> <span class=\"n\">code<\/span> <span class=\"p\">.<\/span> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\"># AWS Profile Switcher<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"kd\">function<\/span><span class=\"w\"> <\/span><span class=\"nb\">Switch-AWSProfile<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"c\"># Get all profiles<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nv\">$profiles<\/span> <span class=\"p\">=<\/span> <span class=\"n\">aws<\/span> <span class=\"n\">configure<\/span> <span class=\"nb\">list-profiles<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"o\">-not<\/span> <span class=\"nv\">$profiles<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nb\">Write-Host<\/span> <span class=\"s2\">&#34;No AWS profiles found.&#34;<\/span> <span class=\"n\">-ForegroundColor<\/span> <span class=\"n\">Red<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">return<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"c\"># Use fzf to select a profile<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nv\">$selectedProfile<\/span> <span class=\"p\">=<\/span> <span class=\"nv\">$profiles<\/span> <span class=\"p\">|<\/span> <span class=\"n\">fzf<\/span> <span class=\"p\">-<\/span><span class=\"n\">-prompt<\/span><span class=\"p\">=<\/span><span class=\"s2\">&#34;Select AWS Profile &gt; &#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"nv\">$selectedProfile<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nv\">$env:AWS_PROFILE<\/span> <span class=\"p\">=<\/span> <span class=\"nv\">$selectedProfile<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nb\">Write-Host<\/span> <span class=\"s2\">&#34;\u2705 Switched to AWS profile: <\/span><span class=\"nv\">$env:AWS_PROFILE<\/span><span class=\"s2\">&#34;<\/span> <span class=\"n\">-ForegroundColor<\/span> <span class=\"n\">Green<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">else<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nb\">Write-Host<\/span> <span class=\"s2\">&#34;\u26a0\ufe0f No profile selected.&#34;<\/span> <span class=\"n\">-ForegroundColor<\/span> <span class=\"n\">Yellow<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\"># GitHub CLI<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"kd\">function<\/span><span class=\"w\"> <\/span><span class=\"nb\">Remove-MergedBranches<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"c\"># Fetch latest changes and prune deleted remote branches<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">git<\/span> <span class=\"n\">fetch<\/span> <span class=\"p\">-<\/span><span class=\"n\">-prune<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"c\"># Get current branch<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nv\">$currentBranch<\/span> <span class=\"p\">=<\/span> <span class=\"n\">git<\/span> <span class=\"nb\">rev-parse<\/span> <span class=\"p\">-<\/span><span class=\"n\">-abbrev-ref<\/span> <span class=\"n\">HEAD<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"c\"># Get merged branches (excluding main\/master and current)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nv\">$mergedBranches<\/span> <span class=\"p\">=<\/span> <span class=\"n\">git<\/span> <span class=\"n\">branch<\/span> <span class=\"p\">-<\/span><span class=\"n\">-merged<\/span> <span class=\"p\">|<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nb\">ForEach-Object<\/span> <span class=\"p\">{<\/span> <span class=\"nv\">$_<\/span><span class=\"p\">.<\/span><span class=\"py\">Trim<\/span><span class=\"p\">()<\/span> <span class=\"p\">}<\/span> <span class=\"p\">|<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nb\">Where-Object<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">(<\/span><span class=\"nv\">$_<\/span> <span class=\"o\">-ne<\/span> <span class=\"s2\">&#34;main&#34;<\/span><span class=\"p\">)<\/span> <span class=\"o\">-and<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">(<\/span><span class=\"nv\">$_<\/span> <span class=\"o\">-ne<\/span> <span class=\"s2\">&#34;master&#34;<\/span><span class=\"p\">)<\/span> <span class=\"o\">-and<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">(<\/span><span class=\"nv\">$_<\/span> <span class=\"o\">-ne<\/span> <span class=\"nv\">$currentBranch<\/span><span class=\"p\">)<\/span> <span class=\"o\">-and<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">(<\/span><span class=\"o\">-not<\/span> <span class=\"nv\">$_<\/span><span class=\"p\">.<\/span><span class=\"py\">StartsWith<\/span><span class=\"p\">(<\/span><span class=\"s2\">&#34;*&#34;<\/span><span class=\"p\">))<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"c\"># Get remote branches<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nv\">$remoteBranches<\/span> <span class=\"p\">=<\/span> <span class=\"n\">git<\/span> <span class=\"n\">branch<\/span> <span class=\"n\">-r<\/span> <span class=\"p\">|<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nb\">ForEach-Object<\/span> <span class=\"p\">{<\/span> <span class=\"nv\">$_<\/span><span class=\"p\">.<\/span><span class=\"py\">Trim<\/span><span class=\"p\">().<\/span><span class=\"py\">Replace<\/span><span class=\"p\">(<\/span><span class=\"s2\">&#34;origin\/&#34;<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&#34;&#34;<\/span><span class=\"p\">)<\/span> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"c\"># Filter merged branches that are deleted from the remote<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nv\">$branchesToDelete<\/span> <span class=\"p\">=<\/span> <span class=\"nv\">$mergedBranches<\/span> <span class=\"p\">|<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nb\">Where-Object<\/span> <span class=\"p\">{<\/span> <span class=\"nv\">$remoteBranches<\/span> <span class=\"o\">-notcontains<\/span> <span class=\"nv\">$_<\/span> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"c\"># Delete the local branches<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">foreach<\/span> <span class=\"p\">(<\/span><span class=\"nv\">$branch<\/span> <span class=\"k\">in<\/span> <span class=\"nv\">$branchesToDelete<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nb\">Write-Host<\/span> <span class=\"s2\">&#34;Deleting local branch: <\/span><span class=\"nv\">$branch<\/span><span class=\"s2\">&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">git<\/span> <span class=\"n\">branch<\/span> <span class=\"n\">-d<\/span> <span class=\"nv\">$branch<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\"># Makefile selector<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"kd\">function<\/span><span class=\"w\"> <\/span><span class=\"nb\">bake<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"c\"># Check if Makefile exists in current directory<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"nb\">Test-Path<\/span> <span class=\"n\">-Path<\/span> <span class=\"s2\">&#34;.\/Makefile&#34;<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"c\"># Extract make targets (rules) from the Makefile<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nv\">$targets<\/span> <span class=\"p\">=<\/span> <span class=\"nb\">Get-Content<\/span> <span class=\"s2\">&#34;.\/Makefile&#34;<\/span> <span class=\"p\">|<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nb\">Select-String<\/span> <span class=\"n\">-Pattern<\/span> <span class=\"s1\">&#39;^([a-zA-Z0-9][a-zA-Z0-9_-]*):&#39;<\/span> <span class=\"p\">|<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nb\">ForEach-Object<\/span> <span class=\"p\">{<\/span> <span class=\"nv\">$_<\/span><span class=\"p\">.<\/span><span class=\"py\">Matches<\/span><span class=\"p\">.<\/span><span class=\"n\">Groups<\/span><span class=\"p\">[<\/span><span class=\"mf\">1<\/span><span class=\"p\">].<\/span><span class=\"py\">Value<\/span> <span class=\"p\">}<\/span> <span class=\"p\">|<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nb\">Sort-Object<\/span> <span class=\"n\">-Unique<\/span> <span class=\"o\">-CaseSensitive<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"c\"># Pipe targets into fzf<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nv\">$selected<\/span> <span class=\"p\">=<\/span> <span class=\"nv\">$targets<\/span> <span class=\"p\">|<\/span> <span class=\"n\">fzf<\/span> <span class=\"p\">-<\/span><span class=\"n\">-prompt<\/span> <span class=\"s2\">&#34;Select Make target: &#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"nv\">$selected<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"c\"># Run the make command<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nv\">$command<\/span> <span class=\"p\">=<\/span> <span class=\"s2\">&#34;make <\/span><span class=\"nv\">$selected<\/span><span class=\"s2\">&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nb\">Write-Host<\/span> <span class=\"s2\">&#34;Running: <\/span><span class=\"nv\">$command<\/span><span class=\"s2\">&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nb\">Invoke-Expression<\/span> <span class=\"nv\">$command<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">else<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nb\">Write-Warning<\/span> <span class=\"s2\">&#34;No Makefile found in the current directory.&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\"># SonarQube<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"kd\">function<\/span><span class=\"w\"> <\/span><span class=\"nb\">ss<\/span> <span class=\"p\">{<\/span> <span class=\"nb\">sonar-scanner<\/span><span class=\"p\">.<\/span><span class=\"py\">bat<\/span> <span class=\"n\">-D<\/span><span class=\"s2\">&#34;sonar.projectKey=<\/span><span class=\"p\">$(<\/span><span class=\"nb\">Get-Location<\/span> <span class=\"p\">|<\/span> <span class=\"nb\">Split-Path<\/span> <span class=\"n\">-Leaf<\/span><span class=\"p\">)<\/span><span class=\"s2\">&#34;<\/span> <span class=\"n\">-D<\/span><span class=\"s2\">&#34;sonar.python.version=3&#34;<\/span> <span class=\"n\">-D<\/span><span class=\"s2\">&#34;sonar.sourceEncoding=UTF-8&#34;<\/span> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\"># Oh My Posh prompt<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nb\">oh-my<\/span><span class=\"n\">-posh<\/span> <span class=\"n\">init<\/span> <span class=\"n\">pwsh<\/span> <span class=\"p\">-<\/span><span class=\"n\">-config<\/span> <span class=\"s2\">&#34;<\/span><span class=\"nv\">$env:POSH_THEMES_PATH<\/span><span class=\"s2\">\/amro.omp.json&#34;<\/span> <span class=\"p\">|<\/span> <span class=\"nb\">Invoke-Expression<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nb\">Import-Module<\/span> <span class=\"nb\">Terminal-Icons<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"nv\">$host<\/span><span class=\"p\">.<\/span><span class=\"py\">Name<\/span> <span class=\"o\">-eq<\/span> <span class=\"s1\">&#39;ConsoleHost&#39;<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nb\">Import-Module<\/span> <span class=\"n\">PSReadLine<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div>","category":[{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/categories\/tech\/","term":"Tech","label":"Tech"}},{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/tags\/setup\/","term":"Setup","label":"Setup"}}]},{"title":"Extract Log Messages from Code using PowerShell","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/extract-log-messages-from-code-using-powershell\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/extract-log-messages-from-code-using-powershell\/","updated":"2026-10-18T02:41:51+00:00","published":"2022-01-23T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"Extract ILogger Messages from Code using PowerShell A co-worker asked how to extract log message from code last week and while I would normally use grep I thought I&rsquo;d improve my PowerShell skills since we use it for so many of our internal scripts at work.","content":"<h1 id=\"extract-ilogger-messages-from-code-using-powershell\">Extract ILogger Messages from Code using PowerShell<\/h1>\n<p>A co-worker asked how to extract log message from code last week and while I would normally use <code>grep<\/code> I thought I&rsquo;d improve my PowerShell skills since we use it for so many of our internal scripts at work.<\/p>\n<p>Our code uses the C# <a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/api\/microsoft.extensions.logging.ilogger?view=dotnet-plat-ext-6.0\">ILogger<\/a> pattern, with a <code>LogXxx()<\/code> method to Exception, Information, and Warning log events, with a GUID for unique code look-up, and a hopefully helpful log message.<\/p>\n<h2 id=\"get-childitems-and-select-string\">Get-ChildItems and Select-String<\/h2>\n<p><code>Get-ChildItems<\/code> and <code>Select-String<\/code> are the backbone of most &ldquo;search in some files for something&rdquo; operations. Think Unix&rsquo;s <code>find<\/code> and <code>grep<\/code>.<\/p>\n<p>My quick and dirty version is meant to be run in the root folder you&rsquo;re gather logs for and captures the filename, log level, GUID and message. I could wrap it into a nice function but&hellip; well, I didn&rsquo;t, mostly because it&rsquo;s Sunday and I&rsquo;d like to jump back into &ldquo;Destiny 2&rdquo; for a bit \ud83d\ude04<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\"> 1\n<\/span><span class=\"lnt\"> 2\n<\/span><span class=\"lnt\"> 3\n<\/span><span class=\"lnt\"> 4\n<\/span><span class=\"lnt\"> 5\n<\/span><span class=\"lnt\"> 6\n<\/span><span class=\"lnt\"> 7\n<\/span><span class=\"lnt\"> 8\n<\/span><span class=\"lnt\"> 9\n<\/span><span class=\"lnt\">10\n<\/span><span class=\"lnt\">11\n<\/span><span class=\"lnt\">12\n<\/span><span class=\"lnt\">13\n<\/span><span class=\"lnt\">14\n<\/span><span class=\"lnt\">15\n<\/span><span class=\"lnt\">16\n<\/span><span class=\"lnt\">17\n<\/span><span class=\"lnt\">18\n<\/span><span class=\"lnt\">19\n<\/span><span class=\"lnt\">20\n<\/span><span class=\"lnt\">21\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-powershell\" data-lang=\"powershell\"><span class=\"line\"><span class=\"cl\"><span class=\"c\"># get a list of all C# files in the current directory and below<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\"># store the results in a variable to use later and to make the<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\"># code easier to read<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nv\">$CodeFiles<\/span> <span class=\"p\">=<\/span> <span class=\"nb\">Get-ChildItem<\/span> <span class=\"n\">-Recurse<\/span> <span class=\"n\">-Path<\/span> <span class=\"p\">.<\/span> <span class=\"o\">-File<\/span> <span class=\"n\">-Filter<\/span> <span class=\"s2\">&#34;*.cs&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\"># match our standard Log messages pattern, shove those results into another variable<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nv\">$LogMessages<\/span> <span class=\"p\">=<\/span> <span class=\"nv\">$CodeFiles<\/span> <span class=\"p\">|<\/span> <span class=\"nb\">Select-String<\/span> <span class=\"n\">-Pattern<\/span> <span class=\"s1\">&#39;Logger\\.Log(.*)\\(\\&#34;(.{36})\\&#34;[^\\&#34;]+\\&#34;([^\\&#34;]+)\\&#34;&#39;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\"># build a temp table and for each log message found above shove the bits<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\"># we care about into it<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nv\">$table<\/span> <span class=\"p\">=<\/span> <span class=\"k\">foreach<\/span> <span class=\"p\">(<\/span><span class=\"nv\">$LogMessage<\/span> <span class=\"k\">in<\/span> <span class=\"nv\">$LogMessages<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nb\">New-Object<\/span> <span class=\"n\">PSObject<\/span> <span class=\"n\">-Property<\/span> <span class=\"vm\">@<\/span><span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">Filename<\/span> <span class=\"p\">=<\/span> <span class=\"nv\">$LogMessage<\/span><span class=\"p\">.<\/span><span class=\"py\">Filename<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">LogLevel<\/span> <span class=\"p\">=<\/span> <span class=\"nv\">$LogMessage<\/span><span class=\"p\">.<\/span><span class=\"py\">Matches<\/span><span class=\"p\">.<\/span><span class=\"n\">Groups<\/span><span class=\"p\">[<\/span><span class=\"mf\">1<\/span><span class=\"p\">].<\/span><span class=\"py\">Value<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">GUID<\/span> <span class=\"p\">=<\/span> <span class=\"nv\">$LogMessage<\/span><span class=\"p\">.<\/span><span class=\"py\">Matches<\/span><span class=\"p\">.<\/span><span class=\"n\">Groups<\/span><span class=\"p\">[<\/span><span class=\"mf\">2<\/span><span class=\"p\">].<\/span><span class=\"py\">Value<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">Message<\/span> <span class=\"p\">=<\/span> <span class=\"nv\">$LogMessage<\/span><span class=\"p\">.<\/span><span class=\"py\">Matches<\/span><span class=\"p\">.<\/span><span class=\"n\">Groups<\/span><span class=\"p\">[<\/span><span class=\"mf\">3<\/span><span class=\"p\">].<\/span><span class=\"py\">Value<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\"># show the world the greatness<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nv\">$table<\/span> <span class=\"p\">|<\/span> <span class=\"nb\">Format-Table<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><p>And here&rsquo;s what the final output looks like:<\/p>\n<pre tabindex=\"0\"><code>Filename LogLevel GUID Message\n-------- -------- ---- -------\nNotificationServiceInterceptor.cs Exception AE4A8E78-A7A8-4C04-B005-C1A23C45B679 Can&#39;t do stuff\nBusinessServiceBase.cs Exception BCDAFE18-9000-0001-ABCD-4A4395F0D8BD Warning Will Robinson, Warning!\n<\/code><\/pre><p>The most difficult thing was the usual learning curve in figuring out how to access the regex capture groups (the <code>GUID<\/code> and <code>Message<\/code> fields).<\/p>\n<h2 id=\"output-to-csv\">Output to CSV<\/h2>\n<p>The table is pretty for the screen but less useful for importing into something like Excel. To dump it to a CSV do either either:<\/p>\n<h3 id=\"to-stdout-the-terminal-screen\">To <code>stdout<\/code> (the terminal screen)<\/h3>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-powershell\" data-lang=\"powershell\"><span class=\"line\"><span class=\"cl\"><span class=\"nv\">$table<\/span> <span class=\"p\">|<\/span> <span class=\"nb\">ConvertTo-Csv<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><h3 id=\"to-a-file\">To a file<\/h3>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-powershell\" data-lang=\"powershell\"><span class=\"line\"><span class=\"cl\"><span class=\"nv\">$table<\/span> <span class=\"p\">|<\/span> <span class=\"nb\">Export-Csv<\/span> <span class=\"n\">-Path<\/span> <span class=\"s2\">&#34;.\\log-messages.csv&#34;<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div>","category":[{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/categories\/code\/","term":"Code","label":"Code"}},{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/tags\/markdown\/","term":"Markdown","label":"Markdown"}},{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/tags\/best-practices\/","term":"Best Practices","label":"Best Practices"}},{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/tags\/csharp\/","term":"Csharp","label":"Csharp"}}]},{"title":"Secure Personal Secrets using Environment Variables and 1Password CLI","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/secure-personal-secrets-using-environment-variables-and-1password-cli\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/secure-personal-secrets-using-environment-variables-and-1password-cli\/","updated":"2022-04-09T00:00:00+00:00","published":"2021-12-05T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"2022.04.08 - - Since writing this a new version of the 1Password CLI came out (2.0) that handles setting environment variables in a much slicker way. The below steps will still work but I suggest checking out the official &ldquo;Load secrets into the environment&rdquo; 1Password CLI docs first.","content":"<blockquote>\n<p>2022.04.08 - - Since writing this a new version of the 1Password CLI came out (2.0) that handles setting environment variables in a much slicker way. The below steps will still work but I suggest checking out the official &ldquo;<a href=\"https:\/\/developer.1password.com\/docs\/cli\/secrets-environment-variables\">Load secrets into the environment<\/a>&rdquo; <a href=\"https:\/\/developer.1password.com\/docs\/cli\">1Password CLI<\/a> docs first.<\/p>\n<p>I also fixed a bunch of spelling mistakes and typos.<\/p>\n<\/blockquote>\n<h1 id=\"secure-personal-secrets-using-environment-variables-and-1password-cli\">Secure Personal Secrets using Environment Variables and 1Password CLI<\/h1>\n<p>At work I spend a lot of time ensuring sensitive access credentials such as passwords, API keys, personal access tokens (PATs) and database connection strings are stored in a secure place that&rsquo;s easy to manage and consume by trusted people and systems. Part of that is never duplicating information, instead pulling it directly from a single, trusted source-of-truth.<\/p>\n<p>Personally I store all my sensitive passwords and keys in 1Password but I still copy\/paste anything that&rsquo;s not a password into various environment variables and configuration files spread across multiple laptops and environments.<\/p>\n<p>I realized just how silly it was to secure my secrets only to expose them to anyone with access to my machines and how much time I wasted ensuring all my environments were configured correctly and up-to-date.<\/p>\n<h2 id=\"automate\">Automate<\/h2>\n<p>Taking a cue from my day job I decided to automate the whole thing in a way that made moving between environments easy and secure, that utilized tools I was already using.<\/p>\n<p>Since 1Password is my source of truth where all my secure information is stored I started there.<\/p>\n<h2 id=\"setup-and-configuration\">Setup and Configuration<\/h2>\n<h3 id=\"install-cli-tools---1password-cli-jq-httpie\">Install CLI tools - 1Password CLI, jq, httpie<\/h3>\n<blockquote>\n<p>2022.04.10 - Another reminder that <a href=\"https:\/\/developer.1password.com\/docs\/cli\">1Password CLI 2<\/a> now handles all of this for you!<\/p>\n<\/blockquote>\n<ol>\n<li><a href=\"https:\/\/support.1password.com\/command-line-getting-started\/\">Install the 1Password CLI<\/a><\/li>\n<li><a href=\"https:\/\/stedolan.github.io\/jq\/download\/\">Install jq<\/a><\/li>\n<li><a href=\"https:\/\/httpie.io\/download\">Install httpie<\/a><\/li>\n<\/ol>\n<p><code>jq<\/code> is a CLI for querying and manipulating JSON, which comes in handy when dealing with REST responses.<\/p>\n<p><code>httpie<\/code> is my preferred <code>curl<\/code> replacement. <code>jq<\/code> and <code>httpie<\/code> aren&rsquo;t strictly required but they&rsquo;re such useful general tools, why not install them?<\/p>\n<h3 id=\"authorize-machine\">Authorize Machine<\/h3>\n<p>The first time you sign into 1Password on a new machine, whether via the desktop, browser extension, or CLI, you provide both your password and secret key. This authorizes the machine with 1Password. Subsequent logins will only require the main password.<\/p>\n<p>Same command for both Windows and Ubuntu:<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><span class=\"lnt\">2\n<\/span><span class=\"lnt\">3\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-powershell\" data-lang=\"powershell\"><span class=\"line\"><span class=\"cl\"><span class=\"c\"># the last two values change depending<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\"># your 1Password account<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"n\">op<\/span> <span class=\"n\">signin<\/span> <span class=\"n\">my<\/span><span class=\"p\">.<\/span><span class=\"py\">1password<\/span><span class=\"p\">.<\/span><span class=\"py\">com<\/span> <span class=\"n\">shawn<\/span><span class=\"p\">.<\/span><span class=\"n\">oster<\/span><span class=\"nv\">@gmail<\/span><span class=\"p\">.<\/span><span class=\"py\">com<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><h3 id=\"add-an-api-credential\">Add an API Credential<\/h3>\n<p>For this example I added my Home Assistant PAT as an API Credential to 1Password.<\/p>\n<p><img src=\"https:\/\/whiskeyandcode.com\/images\/hass_rest.png\" alt=\"1Password API Credential\"><\/p>\n<h3 id=\"retrieve-a-secure-value\">Retrieve a Secure Value<\/h3>\n<p>The 1Password CLI docs do an excellent job explaining ways to work with and retrieve stored values but the basics are:<\/p>\n<ol>\n<li>Request the specific item, by name or UUID<\/li>\n<li>Extract the value to write<\/li>\n<li>Write value as an environment variable, or wherever else it needs to go<\/li>\n<\/ol>\n<p>Dump all values for an entry to get the UUID<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-bash\" data-lang=\"bash\"><span class=\"line\"><span class=\"cl\">op get item HASS_REST <span class=\"p\">|<\/span> jq\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><p>This fetches the entire record for <code>HASS_REST<\/code> as JSON and pipes it through jq to make it easier to read.<\/p>\n<p>There are various ways from here to extract just the needed value, including 1Password&rsquo;s built-in mini query language:<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-bash\" data-lang=\"bash\"><span class=\"line\"><span class=\"cl\">op get item HASS_REST --fields credential\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><h3 id=\"automate-setting-secure-environment-variables\">Automate Setting Secure Environment Variables<\/h3>\n<p>One of the most common uses for secure values, at least for me at home, is setting various environment variables. Given the whole point of this is to automate this whole process I wrote two scripts, one to set environment variables with my personal tokens and another to clear them.<\/p>\n<h4 id=\"securing-a-session\">Securing a session<\/h4>\n<p><strong>PowerShell<\/strong><\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\"> 1\n<\/span><span class=\"lnt\"> 2\n<\/span><span class=\"lnt\"> 3\n<\/span><span class=\"lnt\"> 4\n<\/span><span class=\"lnt\"> 5\n<\/span><span class=\"lnt\"> 6\n<\/span><span class=\"lnt\"> 7\n<\/span><span class=\"lnt\"> 8\n<\/span><span class=\"lnt\"> 9\n<\/span><span class=\"lnt\">10\n<\/span><span class=\"lnt\">11\n<\/span><span class=\"lnt\">12\n<\/span><span class=\"lnt\">13\n<\/span><span class=\"lnt\">14\n<\/span><span class=\"lnt\">15\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-powershell\" data-lang=\"powershell\"><span class=\"line\"><span class=\"cl\"><span class=\"c\"># secure-env.ps1<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\">#<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\"># &#34;Secures&#34; a session by writing sensitive keys as session environment<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\"># variables. Not exactly secure but it does reduce surface area and ensures<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\"># the latest values are always being used<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\"># sign-in to 1Password<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nb\">Invoke-Expression<\/span> <span class=\"vm\">$<\/span><span class=\"p\">(<\/span><span class=\"n\">op<\/span> <span class=\"n\">signin<\/span> <span class=\"n\">my<\/span><span class=\"p\">);<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\"># set HASS_REST env variable<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nb\">Write-Output<\/span> <span class=\"s2\">&#34;Setting Home Assistant REST PAT - HASS_REST...&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nv\">$env:HASS_REST<\/span><span class=\"p\">=<\/span><span class=\"vm\">$<\/span><span class=\"p\">(<\/span><span class=\"n\">op<\/span> <span class=\"n\">get<\/span> <span class=\"n\">item<\/span> <span class=\"n\">HASS_REST<\/span> <span class=\"p\">-<\/span><span class=\"n\">-fields<\/span> <span class=\"n\">credential<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\"># Gladios says hello<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nb\">Write-Output<\/span> <span class=\"s2\">&#34;Unbelievable. You, [subject name here] must be the pride of [subject hometown here.]&#34;<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><p><strong>Ubuntu<\/strong><\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\"> 1\n<\/span><span class=\"lnt\"> 2\n<\/span><span class=\"lnt\"> 3\n<\/span><span class=\"lnt\"> 4\n<\/span><span class=\"lnt\"> 5\n<\/span><span class=\"lnt\"> 6\n<\/span><span class=\"lnt\"> 7\n<\/span><span class=\"lnt\"> 8\n<\/span><span class=\"lnt\"> 9\n<\/span><span class=\"lnt\">10\n<\/span><span class=\"lnt\">11\n<\/span><span class=\"lnt\">12\n<\/span><span class=\"lnt\">13\n<\/span><span class=\"lnt\">14\n<\/span><span class=\"lnt\">15\n<\/span><span class=\"lnt\">16\n<\/span><span class=\"lnt\">17\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-bash\" data-lang=\"bash\"><span class=\"line\"><span class=\"cl\"><span class=\"cp\">#!\/bin\/sh\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"cp\"><\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># secure-env.sh<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c1\">#<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># &#34;Secures&#34; a session by writing sensitive keys as session environment<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># variables. Not exactly secure but it does reduce surface area and ensures<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># the latest values are always being used<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># sign-in to 1Password<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nb\">eval<\/span> <span class=\"k\">$(<\/span>op signin my<span class=\"k\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nb\">echo<\/span> <span class=\"s2\">&#34;Setting Home Assistant REST PAT - HASS_REST...&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nv\">hass_rest_credential<\/span><span class=\"o\">=<\/span><span class=\"k\">$(<\/span>op get item HASS_REST --fields credential<span class=\"k\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nb\">export<\/span> <span class=\"nv\">HASS_REST<\/span><span class=\"o\">=<\/span><span class=\"nv\">$hass_rest_credential<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># Gladios says hello<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nb\">echo<\/span> <span class=\"s2\">&#34;Unbelievable. You, [subject name here] must be the pride of [subject hometown here.]&#34;<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><h3 id=\"test-it\">Test It<\/h3>\n<p>Being able to run the following command was the motivation for this blog post, might as well show it off :) This makes a HTTP POST request to my Home Assistant REST API, secured with a PAT, to turn my office&rsquo;s ceiling light on\/off from the command line. I suppose I could have gotten up and just flipped a switch, but where&rsquo;s the fun in that?<\/p>\n<p><strong>PowerShell<\/strong><\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><span class=\"lnt\">2\n<\/span><span class=\"lnt\">3\n<\/span><span class=\"lnt\">4\n<\/span><span class=\"lnt\">5\n<\/span><span class=\"lnt\">6\n<\/span><span class=\"lnt\">7\n<\/span><span class=\"lnt\">8\n<\/span><span class=\"lnt\">9\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-powershell\" data-lang=\"powershell\"><span class=\"line\"><span class=\"cl\"><span class=\"c\"># sign in, load secure tokens<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">.\/<\/span><span class=\"nb\">secure-env<\/span><span class=\"p\">.<\/span><span class=\"py\">ps1<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\"># use said tokens ($HASS_REST)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"n\">http<\/span> <span class=\"p\">-<\/span><span class=\"n\">-json<\/span> <span class=\"p\">`<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">POST<\/span> <span class=\"n\">http<\/span><span class=\"err\">:<\/span><span class=\"p\">\/\/<\/span><span class=\"n\">monocularjack<\/span><span class=\"p\">.<\/span><span class=\"py\">duckdns<\/span><span class=\"p\">.<\/span><span class=\"n\">org<\/span><span class=\"err\">:<\/span><span class=\"mf\">8123<\/span><span class=\"p\">\/<\/span><span class=\"n\">api<\/span><span class=\"p\">\/<\/span><span class=\"n\">services<\/span><span class=\"p\">\/<\/span><span class=\"n\">light<\/span><span class=\"p\">\/<\/span><span class=\"n\">turn_on<\/span> <span class=\"p\">`<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"s1\">&#39;Content-Type:application\/json&#39;<\/span> <span class=\"p\">`<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"s2\">&#34;Authorization: Bearer <\/span><span class=\"nv\">$env:HASS_REST<\/span><span class=\"s2\">&#34;<\/span> <span class=\"p\">`<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"s1\">&#39;entity_id=light.hue_bulb_office&#39;<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><p><strong>Ubuntu<\/strong><\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><span class=\"lnt\">2\n<\/span><span class=\"lnt\">3\n<\/span><span class=\"lnt\">4\n<\/span><span class=\"lnt\">5\n<\/span><span class=\"lnt\">6\n<\/span><span class=\"lnt\">7\n<\/span><span class=\"lnt\">8\n<\/span><span class=\"lnt\">9\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-bash\" data-lang=\"bash\"><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># sign in, load secure tokens<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">.\/secure-env.sh\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># use said tokens ($HASS_REST)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">http --json <span class=\"se\">\\\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"se\"><\/span> POST http:\/\/monocularjack.duckdns.org:8123\/api\/services\/light\/turn_on <span class=\"se\">\\\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"se\"><\/span> <span class=\"s1\">&#39;Content-Type:application\/json&#39;<\/span> <span class=\"se\">\\\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"se\"><\/span> <span class=\"s2\">&#34;Authorization: Bearer <\/span><span class=\"nv\">$HASS_REST<\/span><span class=\"s2\">&#34;<\/span> <span class=\"se\">\\\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"se\"><\/span> <span class=\"s1\">&#39;entity_id=light.hue_bulb_office&#39;<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><p><strong>Output<\/strong><\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\"> 1\n<\/span><span class=\"lnt\"> 2\n<\/span><span class=\"lnt\"> 3\n<\/span><span class=\"lnt\"> 4\n<\/span><span class=\"lnt\"> 5\n<\/span><span class=\"lnt\"> 6\n<\/span><span class=\"lnt\"> 7\n<\/span><span class=\"lnt\"> 8\n<\/span><span class=\"lnt\"> 9\n<\/span><span class=\"lnt\">10\n<\/span><span class=\"lnt\">11\n<\/span><span class=\"lnt\">12\n<\/span><span class=\"lnt\">13\n<\/span><span class=\"lnt\">14\n<\/span><span class=\"lnt\">15\n<\/span><span class=\"lnt\">16\n<\/span><span class=\"lnt\">17\n<\/span><span class=\"lnt\">18\n<\/span><span class=\"lnt\">19\n<\/span><span class=\"lnt\">20\n<\/span><span class=\"lnt\">21\n<\/span><span class=\"lnt\">22\n<\/span><span class=\"lnt\">23\n<\/span><span class=\"lnt\">24\n<\/span><span class=\"lnt\">25\n<\/span><span class=\"lnt\">26\n<\/span><span class=\"lnt\">27\n<\/span><span class=\"lnt\">28\n<\/span><span class=\"lnt\">29\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-powershell\" data-lang=\"powershell\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">HTTP<\/span><span class=\"p\">\/<\/span><span class=\"mf\">1.1<\/span> <span class=\"mf\">200<\/span> <span class=\"n\">OK<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nb\">Content-Encoding<\/span><span class=\"err\">:<\/span> <span class=\"n\">deflate<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nb\">Content-Length<\/span><span class=\"err\">:<\/span> <span class=\"mf\">277<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nb\">Content-Type<\/span><span class=\"err\">:<\/span> <span class=\"n\">application<\/span><span class=\"p\">\/<\/span><span class=\"n\">json<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"n\">Date<\/span><span class=\"err\">:<\/span> <span class=\"n\">Mon<\/span><span class=\"p\">,<\/span> <span class=\"mf\">06<\/span> <span class=\"n\">Dec<\/span> <span class=\"mf\">2021<\/span> <span class=\"mf\">22<\/span><span class=\"err\">:<\/span><span class=\"mf\">17<\/span><span class=\"err\">:<\/span><span class=\"mf\">06<\/span> <span class=\"n\">GMT<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"n\">Server<\/span><span class=\"err\">:<\/span> <span class=\"n\">Python<\/span><span class=\"p\">\/<\/span><span class=\"mf\">3.9<\/span> <span class=\"n\">aiohttp<\/span><span class=\"p\">\/<\/span><span class=\"mf\">3.7<\/span><span class=\"p\">.<\/span><span class=\"py\">4<\/span><span class=\"p\">.<\/span><span class=\"py\">post0<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">[<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"s2\">&#34;attributes&#34;<\/span><span class=\"err\">:<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"s2\">&#34;friendly_name&#34;<\/span><span class=\"err\">:<\/span> <span class=\"s2\">&#34;Office Ceiling&#34;<\/span><span class=\"p\">,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"s2\">&#34;max_mireds&#34;<\/span><span class=\"err\">:<\/span> <span class=\"mf\">454<\/span><span class=\"p\">,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"s2\">&#34;min_mireds&#34;<\/span><span class=\"err\">:<\/span> <span class=\"mf\">153<\/span><span class=\"p\">,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"s2\">&#34;supported_color_modes&#34;<\/span><span class=\"err\">:<\/span> <span class=\"p\">[<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"s2\">&#34;color_temp&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">],<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"s2\">&#34;supported_features&#34;<\/span><span class=\"err\">:<\/span> <span class=\"mf\">43<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">},<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"s2\">&#34;context&#34;<\/span><span class=\"err\">:<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"s2\">&#34;id&#34;<\/span><span class=\"err\">:<\/span> <span class=\"s2\">&#34;1b2f8d40c8cdcaafe60e1eec4ea13d19&#34;<\/span><span class=\"p\">,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"s2\">&#34;parent_id&#34;<\/span><span class=\"err\">:<\/span> <span class=\"n\">null<\/span><span class=\"p\">,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"s2\">&#34;user_id&#34;<\/span><span class=\"err\">:<\/span> <span class=\"s2\">&#34;9cb3b341377e4c759007eb27c2ad5dc2&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">},<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"s2\">&#34;entity_id&#34;<\/span><span class=\"err\">:<\/span> <span class=\"s2\">&#34;light.hue_bulb_office&#34;<\/span><span class=\"p\">,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"s2\">&#34;last_changed&#34;<\/span><span class=\"err\">:<\/span> <span class=\"s2\">&#34;2021-12-06T22:17:06.319723+00:00&#34;<\/span><span class=\"p\">,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"s2\">&#34;last_updated&#34;<\/span><span class=\"err\">:<\/span> <span class=\"s2\">&#34;2021-12-06T22:17:06.319723+00:00&#34;<\/span><span class=\"p\">,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"s2\">&#34;state&#34;<\/span><span class=\"err\">:<\/span> <span class=\"s2\">&#34;off&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">]<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><h2 id=\"conclusion\">Conclusion<\/h2>\n<p>That&rsquo;s the rough version of how to incorporate a password manager into your daily life without spamming secure keys across all your environments.<\/p>\n<p>A lot has been left to the reader (any me), a few things on my to-do list are:<\/p>\n<ul>\n<li>Create both PowerShell and bash scripts<\/li>\n<li>Write a script to clear variables and log out<\/li>\n<li>Stash the scripts in a public Github repo to make it easier to bootstrap a new machine<\/li>\n<\/ul>\n<p>Have fun and stay secure!<\/p>","category":[{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/categories\/code\/","term":"Code","label":"Code"}},{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/tags\/cli\/","term":"Cli","label":"Cli"}},{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/tags\/security\/","term":"Security","label":"Security"}}]},{"title":"My Approach to Note Taking using Dendron","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/an-opionated-way-to-approach-note-taking\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/an-opionated-way-to-approach-note-taking\/","updated":"2026-10-18T02:41:51+00:00","published":"2021-09-12T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"Using Dendron - An Opionated Approach My Dendron Setup Initialize a Dendron work space Organize notes based on privacy levels Create a storage location for each privacy level Create default templates for each note type Step One - Initialize a Single Dendron Workspace Goals A single location for all notes to reduce location confusion Backup for items not yet commited to a repo Steps Open Visual Studio Code Install the Dendron extension I skip Dendron Markdown Shortcuts because it re-maps Ctrl+B and I&rsquo;m too lazy to re-map and re-learn Run Dendron: Initialize Workspace from the command palette I used \/Dendron at the root of my Dropbox folder for extra backup Step Two - Organize notes based on privacy levels Storing information based on privacy level enforces good privacy practices, increases sharing options, and allows for multiple storage locations with their own access permissions.","content":"<h1 id=\"using-dendron---an-opionated-approach\">Using Dendron - An Opionated Approach<\/h1>\n<h2 id=\"my-dendron-setup\">My Dendron Setup<\/h2>\n<ol>\n<li>Initialize a Dendron work space<\/li>\n<li>Organize notes based on privacy levels<\/li>\n<li>Create a storage location for each privacy level<\/li>\n<li>Create default templates for each note type<\/li>\n<\/ol>\n<h3 id=\"step-one---initialize-a-single-dendron-workspace\">Step One - Initialize a Single Dendron Workspace<\/h3>\n<h4 id=\"goals\">Goals<\/h4>\n<ul>\n<li>A single location for all notes to reduce location confusion<\/li>\n<li>Backup for items not yet commited to a repo<\/li>\n<\/ul>\n<h4 id=\"steps\">Steps<\/h4>\n<ol>\n<li>Open Visual Studio Code<\/li>\n<li>Install the <a href=\"https:\/\/marketplace.visualstudio.com\/items?itemName=dendron.dendron\">Dendron extension<\/a>\n<ul>\n<li>I skip Dendron Markdown Shortcuts because it re-maps <code>Ctrl+B<\/code> and I&rsquo;m too lazy to re-map and re-learn<\/li>\n<\/ul>\n<\/li>\n<li>Run <code>Dendron: Initialize Workspace<\/code> from the command palette\n<ul>\n<li>I used <code>\/Dendron<\/code> at the root of my Dropbox folder for extra backup<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<h3 id=\"step-two---organize-notes-based-on-privacy-levels\">Step Two - Organize notes based on privacy levels<\/h3>\n<p>Storing information based on privacy level enforces good privacy practices, increases sharing options, and allows for multiple storage locations with their own access permissions.<\/p>\n<p>I use three:<\/p>\n<ul>\n<li><code>notes-public<\/code> (public Github repo)\n<ul>\n<li>blog posts<\/li>\n<li>code snippets<\/li>\n<li>reciepes<\/li>\n<\/ul>\n<\/li>\n<li><code>notes-personal<\/code> (private Github repo)\n<ul>\n<li>writing ideas<\/li>\n<li>D&amp;D notes and ideas<\/li>\n<li>setup guides for my personal life<\/li>\n<li>random scratch notes<\/li>\n<\/ul>\n<\/li>\n<li><code>notes-&lt;company&gt;<\/code> (private repo hosted on a company server)\n<ul>\n<li>meeting notes<\/li>\n<li>company-specific setup guides<\/li>\n<li>action items<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>My public and private repos live in a personal Github account and work notes live in a company hosted Azure Repo. This keeps work content seperate from personal while allowing me to pull down my public notes onto my work laptop.<\/p>\n<h3 id=\"step-three---create-a-storage-location-for-each-privacy-level\">Step Three - Create a storage location for each privacy level<\/h3>\n<p>Dendron stores notes in vaults and supports multiple vaults and vault locations. By default are local file-system vault is used, with files stored in the workspace root. It also supports git-based vaults, allowing easier sharing, backup, and providing a single source of truth. It also allows access to your notes on machines that only have a browser.<\/p>\n<p><a href=\"https:\/\/mstempl.netlify.app\/post\/dendron-git\/\">Using Dendron with Github and Git<\/a> provides detailed steps for creating and connecting git-based vaults, here are the cliff notes.<\/p>\n<p>For each privacy level:<\/p>\n<ol>\n<li>Create a new Github repo<\/li>\n<li>Open your Dendron workspace<\/li>\n<li>Add each vault via <code>Dendron: Vault Add<\/code>\n<ul>\n<li>choose <code>remote<\/code> and <code>custom<\/code><\/li>\n<li>enter the clone URL of your repo<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<p>Work vaults should be created inside your company, we use Azure Repos.<\/p>\n<h3 id=\"step-four---initialize-dendron-add-all-three-vaults\">Step Four - Initialize Dendron, Add All Three Vaults<\/h3>\n<p>Follow the excellent guide.<\/p>\n<h3 id=\"step-five---create-templates-for-each-note-type\">Step Five - Create Templates for Each Note Type<\/h3>\n<ul>\n<li>\n<p>notes-public\/templates\/reciepe<\/p>\n<ul>\n<li>adds Food and Reciepe categories<\/li>\n<li>adds Date<\/li>\n<li>Provides basic template<\/li>\n<li>lastupdated<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>notes-public\/templates\/snippet<\/p>\n<\/li>\n<li>\n<p>notes-personal\/templates\/daily<\/p>\n<\/li>\n<li>\n<p>notes-personal\/templates\/writing<\/p>\n<\/li>\n<li>\n<p>notes-personal\/templates\/dnd<\/p>\n<\/li>\n<li>\n<p>notes-personal\/templates\/writing<\/p>\n<\/li>\n<li>\n<p>notes-private\/templates\/diary<\/p>\n<\/li>\n<\/ul>\n<hr>\n<h2 id=\"initiailze-a-dendron-workspace\">Initiailze A Dendron Workspace<\/h2>\n<ol>\n<li>\n<p>Install the <a href=\"https:\/\/marketplace.visualstudio.com\/items?itemName=dendron.dendron\">Dendron VSCode extensions<\/a><\/p>\n<\/li>\n<li><\/li>\n<li>\n<p>I picked my Dropbox root: <code>C:\\Users\\shawn\\Dropbox\\Dendron<\/code><\/p>\n<ul>\n<li>provides an extra layer of backup<\/li>\n<li>follows my existing pattern of using Dropbox as my main user &ldquo;root&rdquo; for documents<\/li>\n<li>making it a folder off the root highlights it&rsquo;s importance<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<h3 id=\"repos-for-work-notes\">Repos for Work Notes<\/h3>\n<ul>\n<li><\/li>\n<\/ul>","category":[{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/categories\/whiskey\/","term":"Whiskey","label":"Whiskey"}},{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/tags\/dendron\/","term":"Dendron","label":"Dendron"}},{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/tags\/knowledge-management\/","term":"Knowledge Management","label":"Knowledge Management"}}]},{"title":"Using Hugo (a static site generator) on a Daily Basis","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/using-hugo-on-a-daily-basis\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/using-hugo-on-a-daily-basis\/","updated":"2026-10-18T02:41:51+00:00","published":"2021-07-12T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"Summary A bunch of tools, heavily inspired by Christian Mohn&rsquo;s My Hugo and Visual Studio Code Workflow, to streamline blogging via Hugo.\nVisual Studio Extensions Markdown Linting David Anson&rsquo;s vscode-markdownlist helps keep your Markdown tidy and it plugs into the Auto Fix... command to quickly cleanup files.","content":"<h2 id=\"summary\">Summary<\/h2>\n<p>A bunch of tools, heavily inspired by Christian Mohn&rsquo;s <a href=\"https:\/\/vninja.net\/2020\/02\/12\/my-hugo-workflow\/\">My Hugo and Visual Studio Code Workflow<\/a>, to streamline blogging via Hugo.<\/p>\n<h2 id=\"visual-studio-extensions\">Visual Studio Extensions<\/h2>\n<h3 id=\"markdown-linting\">Markdown Linting<\/h3>\n<p>David Anson&rsquo;s <a href=\"https:\/\/github.com\/DavidAnson\/vscode-markdownlint\">vscode-markdownlist<\/a> helps keep your Markdown tidy and it plugs into the <code>Auto Fix...<\/code> command to quickly cleanup files.<\/p>\n<h3 id=\"paste-image\">Paste Image<\/h3>\n<p>I agree with Mr. Mohn, <a href=\"https:\/\/github.com\/mushanshitiancai\/vscode-paste-image\">Paste Image<\/a> is a great Markdown image insertion extension. I use the default <code>\/static<\/code> folder to store an <code>\/images<\/code> sub-folder, with relative links in my Markdown.<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><span class=\"lnt\">2\n<\/span><span class=\"lnt\">3\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-bash\" data-lang=\"bash\"><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># my Hugo image and post structure<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\/whiskeyandcode\/content\/posts\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\/whiskeyandcode\/static\/images\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><p>I define my paste settings in a VSCode workspace instead of User since these often change depending on the site.<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><span class=\"lnt\">2\n<\/span><span class=\"lnt\">3\n<\/span><span class=\"lnt\">4\n<\/span><span class=\"lnt\">5\n<\/span><span class=\"lnt\">6\n<\/span><span class=\"lnt\">7\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-json\" data-lang=\"json\"><span class=\"line\"><span class=\"cl\"><span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&#34;pasteImage.path&#34;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&#34;${projectRoot}\\\\static\\\\images\\\\&#34;<\/span><span class=\"p\">,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&#34;pasteImage.basePath&#34;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&#34;${projectRoot}\/static\/images&#34;<\/span><span class=\"p\">,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&#34;pasteImage.showFilePathConfirmInputBox&#34;<\/span><span class=\"p\">:<\/span> <span class=\"kc\">false<\/span><span class=\"p\">,<\/span> <span class=\"err\">#<\/span> <span class=\"err\">set<\/span> <span class=\"err\">to<\/span> <span class=\"err\">true<\/span> <span class=\"err\">for<\/span> <span class=\"nt\">&#34;debugging&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"s2\">&#34;pasteImage.prefix&#34;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&#34;\/images\/&#34;<\/span><span class=\"p\">,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&#34;pasteImage.namePrefix&#34;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&#34;${currentFileNameWithoutExt}_&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><h3 id=\"better-toml-front-matter-formatting\">Better TOML Front Matter Formatting<\/h3>\n<p>I prefer toml for it&rsquo;s concise, single-line array format. To get better toml front matter highlighting install <a href=\"https:\/\/github.com\/bungcip\/better-toml\">Better TOML<\/a>.<\/p>\n<!-- links -->","category":{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/categories\/hugo\/","term":"Hugo","label":"Hugo"}}},{"title":"Running Home Assistant on an Antsle Nano","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/antsle-nano-home-assistant\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/antsle-nano-home-assistant\/","updated":"2026-10-18T02:41:51+00:00","published":"2021-05-11T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"A brief overview of my Home Assistant setup.\nThis is a tour rather than a step-by-step with the goal of reassuring new Antsle owners that you can run all these wonderful things on it and as a reminder to myself for some of the more common setup steps I run.","content":"<p>A brief overview of my <a href=\"https:\/\/www.home-assistant.io\/\">Home Assistant<\/a> setup.<\/p>\n<p>This is a tour rather than a step-by-step with the goal of reassuring new Antsle owners that you can run all these wonderful things on it and as a reminder to myself for some of the more common setup steps I run. I also start with a bit of the &ldquo;why&rdquo;.<\/p>\n<h2 id=\"why-run-a-private-cloud\">Why Run a Private Cloud?<\/h2>\n<p>By a very broad definition I&rsquo;m running an on-prem private cloud. On-prem meaning all the server software runs on my home hardware, storage and network. Why anyone would want to is a very valid question, since the cloud versions of all this would be much easier to work with.<\/p>\n<p>For me it&rsquo;s <strong>privacy and availability<\/strong>.<\/p>\n<h3 id=\"privacy\">Privacy<\/h3>\n<p>The longer I worked at Mighty AI (Seattle, WA ML training data company since acquired by Uber) helping tease out high-quality, data-rich, accurately annotated, training-set data to feed machine learning, the more aware I became of how much of my digital profile I was giving away. While I love having a history of my location throughout the year via my phone&rsquo;s GPS, I don&rsquo;t like Google having first dibs on it. I like even less the idea of a bad actor getting ahold of that data via a Google breach.<\/p>\n<p>Home Assistant allows me to keep a log of my GPS location, sent directly to my server, stored on my disks, and in a raw format allowing me to run my own ML against it. I can share it with other online services but it&rsquo;s now my choice to share it instead of having to ask a 3rd-party to allow another 3rd-party access.<\/p>\n<h3 id=\"availability\">Availability<\/h3>\n<p>I&rsquo;ve experienced my Internet going down too many times to trust in an always-on Internet. I&rsquo;d rather have access to as many of my services and resources on this side of my ISP as possible.<\/p>\n<h2 id=\"hardware---antsle-nano\">Hardware - Antsle Nano<\/h2>\n<p>I run most of my home services off an <a href=\"https:\/\/go.antsle.com\/antsle-nano\/\">Antsle Nano<\/a>, a RasberryPi running Antsle&rsquo;s custom virtualization software that runs Docker and both LXC and KVM images.<\/p>\n<p><img src=\"..\/images\/9ecc9e9fd34c149c60a0666fbb434166aa38574da55e20da2d8576ccedc67af0.png\" alt=\"Antsle Dashboard\"><\/p>\n<p>It&rsquo;s a cute thing isn&rsquo;t it? I have an older Nano with 4GB and I still run a ton of services off of it without issues. Mostly I play with different tech stacks via Ubuntu VMs. It&rsquo;s also fun to see how small of an image I can make and then network dozens of them together to simulate various cloud architectures.<\/p>\n<p>Aside from spinning up quick Linux distros it&rsquo;s plenty powerful enough to run my favorite home automation platform, Home Assistant.<\/p>\n<h2 id=\"software---home-assistant\">Software - Home Assistant<\/h2>\n<p><a href=\"https:\/\/www.home-assistant.io\/\">Home Assistant<\/a> is an open-source home automation platform with a ton of extensibility points and support for pretty much every home IoT device out there.<\/p>\n<p>Since it&rsquo;s a home automation platform it has to be running all the time, making a networked RasberryPi the perfect server to run it on top of. I tried installing it various ways, mostly from source inside of a Ubuntu VM, until I stopped making life hard on myself and switched to the official Docker image.<\/p>\n<p><img src=\"..\/images\/db070fac997ec58105692246a8d988c145edcb466c661df0b2dc7ed51cb8fdb4.png\" alt=\"Home Assistant Dashboard\"><\/p>\n<h3 id=\"installing-home-assistant-on-an-antsle-nano\">Installing Home Assistant on an Antsle Nano<\/h3>\n<p>Installation and basic configuration is a matter of pulling down the Docker image, deleting any old ones if doing an upgrade, then restarting the container.<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\"> 1\n<\/span><span class=\"lnt\"> 2\n<\/span><span class=\"lnt\"> 3\n<\/span><span class=\"lnt\"> 4\n<\/span><span class=\"lnt\"> 5\n<\/span><span class=\"lnt\"> 6\n<\/span><span class=\"lnt\"> 7\n<\/span><span class=\"lnt\"> 8\n<\/span><span class=\"lnt\"> 9\n<\/span><span class=\"lnt\">10\n<\/span><span class=\"lnt\">11\n<\/span><span class=\"lnt\">12\n<\/span><span class=\"lnt\">13\n<\/span><span class=\"lnt\">14\n<\/span><span class=\"lnt\">15\n<\/span><span class=\"lnt\">16\n<\/span><span class=\"lnt\">17\n<\/span><span class=\"lnt\">18\n<\/span><span class=\"lnt\">19\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-bash\" data-lang=\"bash\"><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># ssh into my Antsle Nano<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">ssh root@192.168.1.116\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># pull latest homeassistant image,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># if this returns &#34;Image is up to date&#34; then stop here<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">docker pull homeassistant\/home-assistant:stable\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># stop and remove the running container if<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># doing an upgrade<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">docker stop homeassistant\n<\/span><\/span><span class=\"line\"><span class=\"cl\">docker rm homeassistant\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># start<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">docker run -d --restart<span class=\"o\">=<\/span>always <span class=\"se\">\\\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"se\"><\/span> --name<span class=\"o\">=<\/span>homeassistant <span class=\"se\">\\\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"se\"><\/span> -v \/home\/homeassistant:\/config <span class=\"se\">\\\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"se\"><\/span> -v \/etc\/localtime:\/etc\/localtime:ro <span class=\"se\">\\\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"se\"><\/span> --net<span class=\"o\">=<\/span>host <span class=\"se\">\\\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"se\"><\/span> homeassistant\/home-assistant:stable\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><p>The trickiest part was making sure the time matched the rest of the machines on my home network. The option <code>-v \/etc\/localtime:\/etc\/localtime:ro<\/code> did the trick.<\/p>\n<p><img src=\"..\/images\/ca797f90dbe1cc5970168f10aa39114010c70dfeb440a4e6a542895cabe1aa3b.png\" alt=\"picture 1\"><\/p>\n<h3 id=\"use-vscode-to-edit-home-assistent-config\">Use VSCode to edit Home Assistent Config<\/h3>\n<p>HA stores it&rsquo;s scripts and configurations in a set of yaml files which are mapped to a location on the Nano (<code>-v \/home\/homeassistant:\/config<\/code>). HA has very slick configuration editor but for heavier editing I prefer to use vscode.<\/p>\n<p>I&rsquo;m rather horrible at vi\/vim. so, instead of doing the sane thing and learning it I mount home assistant&rsquo;s config folder into my WSL instance, which I then use <a href=\"https:\/\/github.com\/Microsoft\/vscode-remote-release\">Microsoft&rsquo;s VSCode Remote - WSL extension<\/a> to access.<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><span class=\"lnt\">2\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-bash\" data-lang=\"bash\"><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># map the WSL folder ~\/homeassistant\/ -&gt; \/home\/homeassistant\/ on the Nano<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">sshfs root@192.168.1.116:\/home\/homeassistant\/ ~\/homeassistant\/\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><h3 id=\"accessing-home-assistant-from-the-public-internet\">Accessing Home Assistant from the Public Internet<\/h3>\n<p>Part of the fun of HA is that I can log in from anywhere and control my entire house. To do that you can either pay for Home Assistant Cloud, which handles all the fun, or you can homebrew hack it like I do and use something like duckdns.org.<\/p>\n<p>Nothing too magic here:<\/p>\n<ol>\n<li>\n<p>Reserve IP address via MAC address in router to always use the same IP (this makes things easier, I recommend everyone creates a home network map and reserve IP addresses for all appliances)<\/p>\n<\/li>\n<li>\n<p>Setup dynamic DNS with a service like <a href=\"https:\/\/www.duckdns.org\">DuckDNS.org<\/a><\/p>\n<\/li>\n<li>\n<p>In your router forward port 8123 to the Nano (HA runs on 8123 by default)<\/p>\n<\/li>\n<li>\n<p>Edit <code>configuration.yaml<\/code><\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><span class=\"lnt\">2\n<\/span><span class=\"lnt\">3\n<\/span><span class=\"lnt\">4\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-yaml\" data-lang=\"yaml\"><span class=\"line\"><span class=\"cl\"><span class=\"nt\">homeassistant<\/span><span class=\"p\">:<\/span><span class=\"w\">\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"w\"> <\/span><span class=\"nt\">name<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l\">Home<\/span><span class=\"w\">\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"w\"> <\/span><span class=\"nt\">external_url<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">&#34;http:\/\/&lt;your dynamic DNS subdomain&gt;.duckdns.org:8123&#34;<\/span><span class=\"w\">\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"w\"> <\/span><span class=\"nt\">internal_url<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">&#34;http:\/\/&lt;your internal IP&gt;:8123&#34;<\/span><span class=\"w\">\n<\/span><\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><\/li>\n<\/ol>\n<h2 id=\"software---influxdb\">Software - InfluxDb<\/h2>\n<p>By default HA logs all it&rsquo;s data to a SQLite database. Given the way writes can thrash a SD card it&rsquo;s best to redirect all the data HA generates to something else. There can be more than one &ldquo;some place&rdquo; as well. A common setup is to log to MariaDb for persistance and InfluxDb for time-series based logging and activity.<\/p>\n<p>There are <strong>a lot<\/strong> of great articles out there on InfluxDb and I won&rsquo;t dilute the knowledge pool with my hacked together summary. One thing I did have trouble finding was setting up InfluxDb 2.0 for use with Home Assistant, all while running it on my Nano.<\/p>\n<p>Docker again to the rescue:<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><span class=\"lnt\">2\n<\/span><span class=\"lnt\">3\n<\/span><span class=\"lnt\">4\n<\/span><span class=\"lnt\">5\n<\/span><span class=\"lnt\">6\n<\/span><span class=\"lnt\">7\n<\/span><span class=\"lnt\">8\n<\/span><span class=\"lnt\">9\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-bash\" data-lang=\"bash\"><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># ssh into the Nano first<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">$ docker run -d -p 8086:8086 <span class=\"se\">\\\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"se\"><\/span> -v <span class=\"nv\">$PWD<\/span>\/data:\/var\/lib\/influxdb2 <span class=\"se\">\\\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"se\"><\/span> -v <span class=\"nv\">$PWD<\/span>\/config:\/etc\/influxdb2 <span class=\"se\">\\\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"se\"><\/span> -e <span class=\"nv\">DOCKER_INFLUXDB_INIT_MODE<\/span><span class=\"o\">=<\/span>setup <span class=\"se\">\\\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"se\"><\/span> -e <span class=\"nv\">DOCKER_INFLUXDB_INIT_USERNAME<\/span><span class=\"o\">=<\/span>influx-admin <span class=\"se\">\\\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"se\"><\/span> -e <span class=\"nv\">DOCKER_INFLUXDB_INIT_PASSWORD<\/span><span class=\"o\">=<\/span>EatMoreCupcakesAndTacos <span class=\"se\">\\\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"se\"><\/span> -e <span class=\"nv\">DOCKER_INFLUXDB_INIT_BUCKET<\/span><span class=\"o\">=<\/span>home-assistant <span class=\"se\">\\\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"se\"><\/span> influxdb:latest\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><p>And on the Antsle side, edit <code>configuration.yaml<\/code>:<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\"> 1\n<\/span><span class=\"lnt\"> 2\n<\/span><span class=\"lnt\"> 3\n<\/span><span class=\"lnt\"> 4\n<\/span><span class=\"lnt\"> 5\n<\/span><span class=\"lnt\"> 6\n<\/span><span class=\"lnt\"> 7\n<\/span><span class=\"lnt\"> 8\n<\/span><span class=\"lnt\"> 9\n<\/span><span class=\"lnt\">10\n<\/span><span class=\"lnt\">11\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-yaml\" data-lang=\"yaml\"><span class=\"line\"><span class=\"cl\"><span class=\"c\"># InfluxDB 2.0<\/span><span class=\"w\">\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"w\"><\/span><span class=\"nt\">influxdb<\/span><span class=\"p\">:<\/span><span class=\"w\">\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"w\"> <\/span><span class=\"nt\">api_version<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"m\">2<\/span><span class=\"w\">\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"w\"> <\/span><span class=\"nt\">ssl<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"kc\">false<\/span><span class=\"w\">\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"w\"> <\/span><span class=\"nt\">host<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"m\">192.168.1.116<\/span><span class=\"w\"> <\/span><span class=\"c\"># &lt;- This is my IP, use your own<\/span><span class=\"w\">\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"w\"> <\/span><span class=\"nt\">port<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"m\">8086<\/span><span class=\"w\">\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"w\"> <\/span><span class=\"nt\">organization<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l\">&lt;ID can be found in InfluxDb&gt;<\/span><span class=\"w\">\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"w\"> <\/span><span class=\"nt\">token<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l\">&lt;token from your InfluxDb instance&gt;<\/span><span class=\"w\">\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"w\"> <\/span><span class=\"nt\">bucket<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l\">home-assistant<\/span><span class=\"w\">\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"w\"> <\/span><span class=\"nt\">tags<\/span><span class=\"p\">:<\/span><span class=\"w\">\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"w\"> <\/span><span class=\"nt\">source<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l\">ha<\/span><span class=\"w\">\n<\/span><\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><p>Here&rsquo;s a simple chart of my office temperature as reported via Hue Motion Sensor<\/p>\n<p><img src=\"..\/images\/918d5b22f6834c2982135cf9f56b870e1632f00933de6f1afc9c39135c74df5d.png\" alt=\"InfluxDb\"><\/p>\n<h2 id=\"software---grafana\">Software - Grafana<\/h2>\n<p>Grafana is an amazing open-source visualization platform, yet again Docker to the rescue:<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><span class=\"lnt\">2\n<\/span><span class=\"lnt\">3\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-bash\" data-lang=\"bash\"><span class=\"line\"><span class=\"cl\">docker run -d -p 3100:3000 <span class=\"se\">\\\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"se\"><\/span> --name<span class=\"o\">=<\/span>grafana <span class=\"se\">\\\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"se\"><\/span> -v grafana-storage:\/var\/lib\/grafana grafana\/grafana\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><h2 id=\"devices-configurations-scripts\">Devices, Configurations, Scripts<\/h2>\n<p>There&rsquo;s a lot of other great stuff you can do with Home Assistant and I barely scratch the surface with mine but here&rsquo;s what I have configured.<\/p>\n<ul>\n<li>At 7:45am HA turns on the XBox in my office, starts playing a looping YouTube channel, and turns on my office lights at 70%<\/li>\n<li>Scanning different QR codes will play various artists and playlists via Spotify on my Sonos system<\/li>\n<li>All office temperature data is logged to InfluxDb and Grafana<\/li>\n<li>Integrated <a href=\"https:\/\/owntracks.org\/\">OwnTracks<\/a> to serve as a &ldquo;Find a Friend&rdquo; location service, except the data goes directly to my private cloud<\/li>\n<li>When my partner&rsquo;s phone MAC address is detected on our home network, a bulb in my office blinks twice<\/li>\n<\/ul>","category":[{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/categories\/whiskey\/","term":"Whiskey","label":"Whiskey"}},{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/tags\/home-assistant\/","term":"Home Assistant","label":"Home Assistant"}},{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/tags\/personal-cloud\/","term":"Personal Cloud","label":"Personal Cloud"}}]},{"title":"Fleek.co and Hugo Extended","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/fleek-and-hugo-extended\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/fleek-and-hugo-extended\/","updated":"2024-01-11T02:59:58+00:00","published":"2021-04-25T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"Getting Hugo extended working with Fleek.co hosting","content":"<h1 id=\"fleekco-and-hugo-extended\">Fleek.co and Hugo Extended<\/h1>\n<p>I&rsquo;ve been exploring distributed low-level systems, such as transport protocols, packet-level encryption, and immutability in a decentralized system (blockchain). Part of that is rebooting my blog and hosting it via <a href=\"https:\/\/fleek.co\/\">Fleek<\/a> over the <a href=\"https:\/\/ipfs.io\/\">IPFS<\/a> protocol.<\/p>\n<p>Hugo is my static site generator of choice and <a href=\"https:\/\/blog.fleek.co\/posts\/go-with-hugo-and-fleek\">Go with Hugo and Fleek<\/a> is a great tutorial to get started. Everything worked pretty much as advertised until I picked a theme, <a href=\"https:\/\/themes.gohugo.io\/hugo-theme-meme\/\">MemE<\/a>, that required the extended version of Hugo that supports Sass\/SCSS.<\/p>\n<h2 id=\"build-a-custom-docker-image-from-fleeks-dockerfile\">Build a Custom Docker Image From Fleek&rsquo;s Dockerfile<\/h2>\n<p>Fleek&rsquo;s deployment pipeline allows the use of any Docker Hub image as the binary in a site&rsquo;s build step. The supported build systems are Docker images, with their Dockerfile&rsquo;s helpfully committed to Github.<\/p>\n<p>I cloned the official Dockerfiles, updated them to point to Hugo extended, and published a new Docker image to use in the deployment settings on Fleek.<\/p>\n<h3 id=\"create-docker-repository\">Create Docker repository<\/h3>\n<p>Fleek only accepts public Docker images hosted on Docker Hub, so sign-up for a free account if you don&rsquo;t have one. You get one free repository per account (or is it one image? IDK, I only needed one).<\/p>\n<ol>\n<li>Create a new repository: <code>&lt;docker username&gt;\/huge-extended-for-fleek<\/code>.<\/li>\n<\/ol>\n<h3 id=\"create-dockerfile-file\">Create Dockerfile file<\/h3>\n<p>I&rsquo;m doing this on a Windows box but the steps are basic enough that they should work everywhere, with appropriate tweaks.<\/p>\n<ol>\n<li>\n<p>Grab the latest Hugo Dockerfile from <a href=\"https:\/\/github.com\/FleekHQ\/site-builder-docker-images\">Fleek&rsquo;s Docker Image Github repo<\/a><\/p>\n<\/li>\n<li>\n<p>Created a new folder to stash the Dockerfile<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><span class=\"lnt\">2\n<\/span><span class=\"lnt\">3\n<\/span><span class=\"lnt\">4\n<\/span><span class=\"lnt\">5\n<\/span><span class=\"lnt\">6\n<\/span><span class=\"lnt\">7\n<\/span><span class=\"lnt\">8\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-powershell\" data-lang=\"powershell\"><span class=\"line\"><span class=\"cl\"><span class=\"c\"># these are simplified paths, in practice I use Dropbox to keep my files casually backed-up<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\"># and put all source-type files under a \\source folder.<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\">#<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\"># # where it lives on my machine:<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\"># C:\\Users\\Shawn\\Dropbox\\source\\docker\\hugo-extended-for-fleek<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\">#<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"n\">mkdir<\/span> <span class=\"n\">c:<\/span><span class=\"p\">\\<\/span><span class=\"n\">repos<\/span><span class=\"p\">\\<\/span><span class=\"n\">docker<\/span><span class=\"p\">\\<\/span><span class=\"nb\">hugo-extended<\/span><span class=\"n\">-for-fleek<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nb\">cd <\/span><span class=\"n\">c:<\/span><span class=\"p\">\\<\/span><span class=\"n\">repos<\/span><span class=\"p\">\\<\/span><span class=\"n\">docker<\/span><span class=\"p\">\\<\/span><span class=\"nb\">hugo-extended<\/span><span class=\"n\">-for-fleek<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><\/li>\n<li>\n<p>Added <code>_extended<\/code> into the <code>wget<\/code> call to pull the extended version from <a href=\"https:\/\/github.com\/gohugoio\/hugo\/releases\">Hugo&rsquo;s release page<\/a>. The default image allows passing in the <code>node<\/code> version but Hugo doesn&rsquo;t care so I went with latest.<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\"> 1\n<\/span><span class=\"lnt\"> 2\n<\/span><span class=\"lnt\"> 3\n<\/span><span class=\"lnt\"> 4\n<\/span><span class=\"lnt\"> 5\n<\/span><span class=\"lnt\"> 6\n<\/span><span class=\"lnt\"> 7\n<\/span><span class=\"lnt\"> 8\n<\/span><span class=\"lnt\"> 9\n<\/span><span class=\"lnt\">10\n<\/span><span class=\"lnt\">11\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-docker\" data-lang=\"docker\"><span class=\"line\"><span class=\"cl\"><span class=\"k\">FROM<\/span><span class=\"s\"> node:latest<\/span><span class=\"err\">\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"err\">\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"err\"><\/span><span class=\"k\">ARG<\/span> <span class=\"nv\">HUGO_VERSION<\/span><span class=\"o\">=<\/span><span class=\"m\">0<\/span>.122.0<span class=\"err\">\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"err\">\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"err\"><\/span><span class=\"k\">RUN<\/span> apt-get update <span class=\"o\">&amp;&amp;<\/span> apt-get install -y wget<span class=\"err\">\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"err\">\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"err\"><\/span><span class=\"k\">RUN<\/span> wget https:\/\/github.com\/gohugoio\/hugo\/releases\/download\/v<span class=\"si\">${<\/span><span class=\"nv\">HUGO_VERSION<\/span><span class=\"si\">}<\/span>\/hugo_extended_<span class=\"si\">${<\/span><span class=\"nv\">HUGO_VERSION<\/span><span class=\"si\">}<\/span>_Linux-64bit.tar.gz <span class=\"o\">&amp;&amp;<\/span> <span class=\"se\">\\\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"se\"><\/span> tar -xf hugo_extended_<span class=\"si\">${<\/span><span class=\"nv\">HUGO_VERSION<\/span><span class=\"si\">}<\/span>_Linux-64bit.tar.gz -C \/usr\/local\/bin <span class=\"o\">&amp;&amp;<\/span> <span class=\"se\">\\\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"se\"><\/span> hugo version <span class=\"o\">&amp;&amp;<\/span> rm hugo_extended_<span class=\"si\">${<\/span><span class=\"nv\">HUGO_VERSION<\/span><span class=\"si\">}<\/span>_Linux-64bit.tar.gz<span class=\"err\">\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"err\">\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"err\"><\/span><span class=\"k\">RUN<\/span> wget -q -O - https:\/\/raw.githubusercontent.com\/canha\/golang-tools-install-script\/master\/goinstall.sh <span class=\"p\">|<\/span> bash<span class=\"err\">\n<\/span><\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><\/li>\n<li>\n<p>Build the image<\/p>\n<p><strong>Ubuntu<\/strong><\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><span class=\"lnt\">2\n<\/span><span class=\"lnt\">3\n<\/span><span class=\"lnt\">4\n<\/span><span class=\"lnt\">5\n<\/span><span class=\"lnt\">6\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-bash\" data-lang=\"bash\"><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># there are needed to avoid using Docker buildkit,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># which breaks many things<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nb\">export<\/span> <span class=\"nv\">DOCKER_BUILDKIT<\/span><span class=\"o\">=<\/span><span class=\"m\">0<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nb\">export<\/span> <span class=\"nv\">COMPOSE_DOCKER_CLI_BUILD<\/span><span class=\"o\">=<\/span><span class=\"m\">0<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\">docker build . -t &lt;your docker username&gt;\/hugo-extended-for-fleek:122.0\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><p><strong>PowerShell<\/strong><\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><span class=\"lnt\">2\n<\/span><span class=\"lnt\">3\n<\/span><span class=\"lnt\">4\n<\/span><span class=\"lnt\">5\n<\/span><span class=\"lnt\">6\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-powershell\" data-lang=\"powershell\"><span class=\"line\"><span class=\"cl\"><span class=\"c\"># there are needed to avoid using Docker buildkit,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c\"># which breaks many things<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nv\">$env:DOCKER_BUILDKIT<\/span><span class=\"p\">=<\/span><span class=\"mf\">0<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nv\">$env:COMPOSE_DOCKER_CLI_BUILD<\/span><span class=\"p\">=<\/span><span class=\"mf\">0<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"n\">docker<\/span> <span class=\"n\">build<\/span> <span class=\"p\">.<\/span> <span class=\"n\">-t<\/span> <span class=\"p\">&lt;<\/span><span class=\"n\">your<\/span> <span class=\"n\">docker<\/span> <span class=\"n\">username<\/span><span class=\"p\">&gt;\/<\/span><span class=\"nb\">hugo-extended<\/span><span class=\"n\">-for-fleek:<\/span><span class=\"mf\">122.0<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><\/li>\n<\/ol>\n<h3 id=\"publish-docker-image\">Publish Docker image<\/h3>\n<ol>\n<li>\n<p>Publish it to Docker Hub<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-bash\" data-lang=\"bash\"><span class=\"line\"><span class=\"cl\">docker push &lt;your docker username&gt;\/hugo-extended-for-fleek:122.0\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><\/li>\n<\/ol>\n<h3 id=\"use-new-docker-image\">Use new Docker image<\/h3>\n<ol>\n<li>Find your site under the Hosting section on <a href=\"https:\/\/fleek.co\/\">Fleek.co<\/a><\/li>\n<li>Go to Settings -&gt; Build &amp; Deploy -&gt; Specify Docker Image<\/li>\n<li>Edit Settings<\/li>\n<li>Replace contents with <code>&lt;your docker username&gt;\/hugo-extended-for-fleek:122.0<\/code>\n<ul>\n<li>(or use mine: <code>shawnoster\/hugo-extended-for-fleek:122.0<\/code>)<\/li>\n<\/ul>\n<\/li>\n<li>Trigger a new deploy<\/li>\n<\/ol>\n<p><img src=\"https:\/\/whiskeyandcode.com\/images\/fleek-and-hugo-extended_2021-07-13-17-09-55.png\" alt=\"\"><\/p>\n<h2 id=\"done\">Done<\/h2>\n<p>And that&rsquo;s that.<\/p>\n<p>There are lots of great hugo images out there but the ones I found all required some fiddling to get them to work w\/ Fleek.co while this image could be optimized it does work seamlessly with Fleek.co.<\/p>\n<p>You can always skip the above steps and use the image directly if you&rsquo;re looking for a drop-in replacement.<\/p>\n<p><strong>Huge Extended (85.0) for use with Fleek.co:<\/strong> <a href=\"https:\/\/hub.docker.com\/r\/shawnoster\/hugo-extended-for-fleek\">shawnoster\/hugo-extended-for-fleek<\/a><\/p>","category":{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/categories\/hugo\/","term":"Hugo","label":"Hugo"}}},{"title":"WP8 XAML App Development at Build 2012","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/wp8-xaml-app-development-build-2012\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/wp8-xaml-app-development-build-2012\/","updated":"2026-10-18T02:41:51+00:00","published":"2012-11-03T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"I gave my Build 2012 talk this week and it was all around WP8 XAML app development showing off some of cool new features in the XAML platform that you can incorporate into your apps.\nA huge thanks to all the people that showed up, gave feedback and asked questions!","content":"<p>I gave my <a href=\"http:\/\/www.buildwindows.com\/\">Build 2012<\/a> talk this week and it was all around WP8 XAML app development showing off some of cool new features in the XAML platform that you can incorporate into your apps.<\/p>\n<p>A huge thanks to all the people that showed up, gave feedback and asked questions! I know a few people asked me questions via e-mail &amp; twitter and if I missed your question apologies, I&rsquo;ll be more than happy to answer any remaining ones now that things have calmed down a little. I wasn&rsquo;t able to go into deep detail on everything I wanted to so if there was something you want to see more of just drop me a comment.<\/p>\n<p>The talk, like all the other great Build talks, was recorded and is <a href=\"http:\/\/channel9.msdn.com\/Events\/Build\/2012\/2-021\">available to watch<\/a> directly from channel9 or you can download it and watch it offline.\u00a0 I&rsquo;ve also posted the source for my demo and the deck itself.\u00a0 Some parts of the source may look a little different from the demo and that&rsquo;s because I cleaned it up and streamlined it some, I have a hard time sometimes leaving code as is, especially if I see a way to make it better.<\/p>\n<p><a href=\"http:\/\/bit.ly\/YgMLdo\">Download Source + Deck for WP8 XAML App Development<\/a> (hosted on Azure!)<\/p>\n<iframe style=\"height: 540px; width: 960px\" src=\"http:\/\/channel9.msdn.com\/Events\/Build\/2012\/2-021\/player?w=960&h=540\" frameborder=\"0\" scrolling=\"no\"><\/iframe>","category":{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/categories\/windows-phone\/","term":"Windows Phone","label":"Windows Phone"}}},{"title":"Windows Phone Toolkit - September 2012 Release","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/windows-phone-toolkit-september-2012-release\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/windows-phone-toolkit-september-2012-release\/","updated":"2026-10-18T02:41:51+00:00","published":"2012-10-15T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"A few astute people (@Patric68,\u00a0@scottisafool) have noticed that we pushed out the September 2012 release of the Windows Phone Toolkit.\u00a0This was a soft launch, quietly pushed out because we&rsquo;ve been going like crazy with bug fixes, prepping for Build and doing a whole host of things and I really wanted to get a build out that had the latest fixes and improvements without blocking on all the paperwork.","content":"<p>A few astute people (<a href=\"http:\/\/twitter.com\/Patric68\">@Patric68<\/a>,\u00a0 <a href=\"http:\/\/twitter.com\/scottisafool\">@scottisafool<\/a>) have noticed that we pushed out the <a href=\"http:\/\/silverlight.codeplex.com\/releases\/view\/94435\">September 2012 release of the Windows Phone Toolkit<\/a>.\u00a0 This was a soft launch, quietly pushed out because we&rsquo;ve been going like crazy with bug fixes, prepping for <a href=\"http:\/\/www.buildwindows.com\/\">Build<\/a> and doing a whole host of things and I really wanted to get a build out that had the latest fixes and improvements without blocking on all the paperwork. That&rsquo;s agile baby!<\/p>\n<h2 id=\"whats-new\">What&rsquo;s New<\/h2>\n<h2 id=\"branding\">Branding<\/h2>\n<p>It&rsquo;s now just the &ldquo;Windows Phone Toolkit&rdquo;.\u00a0 Honestly &ldquo;Silverlight for Windows Phone Toolkit&rdquo; was too much of a mouthful and new developers targeting Windows Phone often don&rsquo;t know of the Silverlight underpinnings.\u00a0 We&rsquo;re slowly transitioning all branding in the source to the shorter version.<\/p>\n<h2 id=\"custommessagebox\">CustomMessageBox<\/h2>\n<p><img src=\"https:\/\/whiskeyandcode.com\/images\/SampleMessageBox.png\" alt=\"Sample CustomMessageBox Image\" title=\"CustomMessageBox\"><\/p>\n<p>CustomMessageBox is a new control that makes it easy to create, well, custom message boxes that look and feel just like the default ones on the phone.\u00a0 I did a little write-up of it last week in my blog post, &ldquo;<a href=\"https:\/\/whiskeyandcode.com\/posts\/welcome-custommessagebox-to-the-windows-phone-toolkit\/\">Welcome CustomMessageBox to the Windows Phone Toolkit<\/a>&rdquo;.<\/p>\n<h2 id=\"rating\">Rating<\/h2>\n<p><img src=\"https:\/\/whiskeyandcode.com\/images\/SampleRatingControl.png\" alt=\"Sample Rating Control Image\" title=\"Rating\"><\/p>\n<p>Rating is another new control that does exactly what it says, provides a rating control that matches the Windows Phone UI.\u00a0 Expect a blog post on using it soon but it as always you can see it in action by downloading the sample application from <a href=\"http:\/\/silverlight.codeplex.com\">CodePlex<\/a>.<\/p>\n<h2 id=\"transition-effects\">Transition Effects<\/h2>\n<p>There are new transition effects that make it even easier to match the Windows Phone UX.<\/p>\n<ul>\n<li>SlideInEffect - Ever notice when you&rsquo;re in a Pivot or Panorama on the phone in one of the native experiences , say the People Hub, how the items in a list slide in on a separate animation as you swipe back and forth?\u00a0 It&rsquo;s subtle but adds a nice level of polish to the whole experience and now it&rsquo;s super easy to add to your application as well.\u00a0 There is a new attached property, toolkit:SlideInEffect that you set on each item in your DataTemplate that controls the order in which elements slide in:<\/li>\n<\/ul>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\"> 1\n<\/span><span class=\"lnt\"> 2\n<\/span><span class=\"lnt\"> 3\n<\/span><span class=\"lnt\"> 4\n<\/span><span class=\"lnt\"> 5\n<\/span><span class=\"lnt\"> 6\n<\/span><span class=\"lnt\"> 7\n<\/span><span class=\"lnt\"> 8\n<\/span><span class=\"lnt\"> 9\n<\/span><span class=\"lnt\">10\n<\/span><span class=\"lnt\">11\n<\/span><span class=\"lnt\">12\n<\/span><span class=\"lnt\">13\n<\/span><span class=\"lnt\">14\n<\/span><span class=\"lnt\">15\n<\/span><span class=\"lnt\">16\n<\/span><span class=\"lnt\">17\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-xml\" data-lang=\"xml\"><span class=\"line\"><span class=\"cl\"><span class=\"nt\">&lt;DataTemplate&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;StackPanel<\/span> <span class=\"na\">Margin=<\/span><span class=\"s\">&#34;0,0,0,17&#34;<\/span> <span class=\"na\">Width=<\/span><span class=\"s\">&#34;432&#34;<\/span><span class=\"nt\">&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;TextBlock<\/span> <span class=\"na\">Text=<\/span><span class=\"s\">&#34;{Binding LineOne}&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">TextWrapping=<\/span><span class=\"s\">&#34;Wrap&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">Style=<\/span><span class=\"s\">&#34;{StaticResource PhoneTextExtraLargeStyle}&#34;<\/span><span class=\"nt\">\/&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;TextBlock<\/span> <span class=\"na\">Text=<\/span><span class=\"s\">&#34;{Binding LineTwo}&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">TextWrapping=<\/span><span class=\"s\">&#34;Wrap&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">Margin=<\/span><span class=\"s\">&#34;12,-6,12,0&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">Style=<\/span><span class=\"s\">&#34;{StaticResource PhoneTextAccentStyle}&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">toolkit:SlideInEffect.LineIndex=<\/span><span class=\"s\">&#34;1&#34;<\/span><span class=\"nt\">\/&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;TextBlock<\/span> <span class=\"na\">Text=<\/span><span class=\"s\">&#34;{Binding LineTwo}&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">TextWrapping=<\/span><span class=\"s\">&#34;Wrap&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">Margin=<\/span><span class=\"s\">&#34;12,-6,12,0&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">Style=<\/span><span class=\"s\">&#34;{StaticResource PhoneTextSubtleStyle}&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">toolkit:SlideInEffect.LineIndex=<\/span><span class=\"s\">&#34;2&#34;<\/span><span class=\"nt\">\/&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;\/StackPanel&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nt\">&lt;\/DataTemplate&gt;<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><ul>\n<li>FeatherTransition - Another common effect seen on Windows Phone is a &ldquo;feathering&rdquo; in of the controls on a page such as when you launch the mail app.\u00a0 Notice how the items on the page feather in from top to bottom.<\/li>\n<\/ul>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\"> 1\n<\/span><span class=\"lnt\"> 2\n<\/span><span class=\"lnt\"> 3\n<\/span><span class=\"lnt\"> 4\n<\/span><span class=\"lnt\"> 5\n<\/span><span class=\"lnt\"> 6\n<\/span><span class=\"lnt\"> 7\n<\/span><span class=\"lnt\"> 8\n<\/span><span class=\"lnt\"> 9\n<\/span><span class=\"lnt\">10\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-xml\" data-lang=\"xml\"><span class=\"line\"><span class=\"cl\"><span class=\"c\">&lt;!--TitlePanel--&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nt\">&lt;StackPanel<\/span> <span class=\"na\">Grid.Row=<\/span><span class=\"s\">&#34;0&#34;<\/span> <span class=\"na\">Margin=<\/span><span class=\"s\">&#34;12,17,0,28&#34;<\/span><span class=\"nt\">&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;TextBlock<\/span> <span class=\"na\">Text=<\/span><span class=\"s\">&#34;{StaticResource ApplicationTitle}&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">Style=<\/span><span class=\"s\">&#34;{StaticResource PhoneTextNormalStyle}&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">toolkit:TurnstileFeatherEffect.FeatheringIndex=<\/span><span class=\"s\">&#34;0&#34;<\/span><span class=\"nt\">\/&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;TextBlock<\/span> <span class=\"na\">Text=<\/span><span class=\"s\">&#34;turnstilefeathereffect&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">Margin=<\/span><span class=\"s\">&#34;9,-7,0,0&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">Style=<\/span><span class=\"s\">&#34;{StaticResource PhoneTextTitle1Style}&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">toolkit:TurnstileFeatherEffect.FeatheringIndex=<\/span><span class=\"s\">&#34;1&#34;<\/span><span class=\"nt\">\/&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nt\">&lt;\/StackPanel&gt;<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><h2 id=\"distribution--installation\">Distribution \/ Installation<\/h2>\n<p>We&rsquo;ve taken a new approach to distribution this time and gone &ldquo;all-in&rdquo; on <a href=\"http:\/\/nuget.org\">NuGet<\/a> as the official way to <a href=\"http:\/\/nuget.org\/packages\/SilverlightToolkitWP\">install the toolkit<\/a>.\u00a0 We&rsquo;ll no longer be supporting an MSI-based installer as it&rsquo;s not very maintainable or discoverable.\u00a0 NuGet is built into Visual Studio 2012 and is fast becoming the de-facto standard for installing packages and if you haven&rsquo;t already installed the plug-in for Visual Studio 2010 I highly recommend it.<\/p>\n<p>As always you can still either download the source as a zip or from the source control on CodePlex and compiling the assembly yourself.<\/p>\n<h2 id=\"bug-fixes\">Bug Fixes<\/h2>\n<p>No release is complete without bug fixes and we have roughly 25 of the top user voted bugs fixed in this release.<\/p>\n<h2 id=\"feedback\">Feedback<\/h2>\n<p>As always we love feedback, bug reports, creative uses and ideas.\u00a0 We have more plans for the toolkit in the near future as well so stay tuned!<\/p>","category":{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/categories\/windows-phone\/","term":"Windows Phone","label":"Windows Phone"}}},{"title":"Welcome CustomMessageBox to the Windows Phone Toolkit","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/welcome-custommessagebox-to-the-windows-phone-toolkit\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/welcome-custommessagebox-to-the-windows-phone-toolkit\/","updated":"2026-10-18T02:41:51+00:00","published":"2012-10-01T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"A big welcome to CustomMessageBox, a new control to the toolkit which is exactly what it sounds like, a customizable, Windows Phone-UI compliant, easy to use message box offering the following features:\nNative look &amp; feel including font sizes, layout, alignment and animations Ability to display full screen or to only consume as much space as needed Very simple &ldquo;basic&rdquo; mode with ability to easily extend it to complex scenarios Customizable buttons without needing to re-template Here is what it looks like, from the basic (a message and some buttons) to the complex (a full screen message box with an embedded Pivot):","content":"<p>A big welcome to CustomMessageBox, a new control to the toolkit which is exactly what it sounds like, a customizable, Windows Phone-UI compliant, easy to use message box offering the following features:<\/p>\n<ul>\n<li>Native look &amp; feel including font sizes, layout, alignment and animations<\/li>\n<li>Ability to display full screen or to only consume as much space as needed<\/li>\n<li>Very simple &ldquo;basic&rdquo; mode with ability to easily extend it to complex scenarios<\/li>\n<li>Customizable buttons without needing to re-template<\/li>\n<\/ul>\n<p>Here is what it looks like, from the basic (a message and some buttons) to the complex (a full screen message box with an embedded Pivot):<\/p>\n<p><a href=\"https:\/\/whiskeyandcode.com\/images\/image_10.png\"><img src=\"https:\/\/whiskeyandcode.com\/images\/image_thumb_10.png\" alt=\"image\" title=\"image\"><\/a><a href=\"https:\/\/whiskeyandcode.com\/images\/image_11.png\"><img src=\"https:\/\/whiskeyandcode.com\/images\/image_thumb_11.png\" alt=\"image\" title=\"image\"><\/a><\/p>\n<h2 id=\"getting-started\">Getting Started<\/h2>\n<p>As of today (9\/30\/2012) you&rsquo;ll need to download the <a href=\"http:\/\/silverlight.codeplex.com\/\">latest source from CodePlex<\/a> and recompile the toolkit assembly to use it but we&rsquo;ll soon have an updated NuGet package for your convenience. As usual add a reference to the Microsoft.Phone.Controls.Toolkit.dll to your project and add the toolkit XML namespace to the top of your XAML:<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-xml\" data-lang=\"xml\"><span class=\"line\"><span class=\"cl\">xmlns:toolkit=&#34;clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit&#34;\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><h2 id=\"basic-usage\">Basic Usage<\/h2>\n<p>The basic usage is very similar to the default MessageBox and how you&rsquo;re probably used to using dialogs in other UI platforms; set some properties, call Show(), handle the event that is raised when the user returns from the dialog.<\/p>\n<p>Possible values to customize are:<\/p>\n<ul>\n<li><code>Caption<\/code> - sets the title caption of the message box<\/li>\n<li><code>Message<\/code> - the actual message to display to the user<\/li>\n<li><code>LeftButtonContent<\/code>, <code>RightButtonContent<\/code> - the buttons that appear on the bottom of the dialog, if you omit the text then the button won&rsquo;t be shown.<\/li>\n<\/ul>\n<p>To handle the user&rsquo;s selection hook up the <code>Dismissed()<\/code> event and look at the <code>e.Result<\/code> value which is of type <code>CustomMessageBoxResult<\/code> indicating which, if any, button was tapped. If the user presses the back button vs. making a selection the result will be None.<\/p>\n<p>Finally to kick-off the whole process call <code>Show()<\/code>. <code>Show()<\/code> is non-blocking so be aware that any code you put after the <code>Show()<\/code> call will run before the user has made a selection.<\/p>\n<p>By default the the message box only takes up as much space as required but you can force it to full-screen by setting the property <code>IsFullScreen<\/code> to true.<\/p>\n<h2 id=\"simple-example\">Simple Example<\/h2>\n<p>To recreate the first message box in the screen shot do the following in code-behind:<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\"> 1\n<\/span><span class=\"lnt\"> 2\n<\/span><span class=\"lnt\"> 3\n<\/span><span class=\"lnt\"> 4\n<\/span><span class=\"lnt\"> 5\n<\/span><span class=\"lnt\"> 6\n<\/span><span class=\"lnt\"> 7\n<\/span><span class=\"lnt\"> 8\n<\/span><span class=\"lnt\"> 9\n<\/span><span class=\"lnt\">10\n<\/span><span class=\"lnt\">11\n<\/span><span class=\"lnt\">12\n<\/span><span class=\"lnt\">13\n<\/span><span class=\"lnt\">14\n<\/span><span class=\"lnt\">15\n<\/span><span class=\"lnt\">16\n<\/span><span class=\"lnt\">17\n<\/span><span class=\"lnt\">18\n<\/span><span class=\"lnt\">19\n<\/span><span class=\"lnt\">20\n<\/span><span class=\"lnt\">21\n<\/span><span class=\"lnt\">22\n<\/span><span class=\"lnt\">23\n<\/span><span class=\"lnt\">24\n<\/span><span class=\"lnt\">25\n<\/span><span class=\"lnt\">26\n<\/span><span class=\"lnt\">27\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-csharp\" data-lang=\"csharp\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">CustomMessageBox<\/span> <span class=\"n\">messageBox<\/span> <span class=\"p\">=<\/span> <span class=\"k\">new<\/span> <span class=\"n\">CustomMessageBox<\/span><span class=\"p\">()<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">Caption<\/span> <span class=\"p\">=<\/span> <span class=\"s\">&#34;Do you like this sample?&#34;<\/span><span class=\"p\">,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">Message<\/span> <span class=\"p\">=<\/span> <span class=\"s\">&#34;There are tons of things you can do using custom message boxes. To learn more, be sure to check out the source code at CodePlex.&#34;<\/span><span class=\"p\">,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">LeftButtonContent<\/span> <span class=\"p\">=<\/span> <span class=\"s\">&#34;yes&#34;<\/span><span class=\"p\">,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">RightButtonContent<\/span> <span class=\"p\">=<\/span> <span class=\"s\">&#34;no&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">};<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"n\">messageBox<\/span><span class=\"p\">.<\/span><span class=\"n\">Dismissed<\/span> <span class=\"p\">+=<\/span> <span class=\"p\">(<\/span><span class=\"n\">s1<\/span><span class=\"p\">,<\/span> <span class=\"n\">e1<\/span><span class=\"p\">)<\/span> <span class=\"p\">=&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">switch<\/span> <span class=\"p\">(<\/span><span class=\"n\">e1<\/span><span class=\"p\">.<\/span><span class=\"n\">Result<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">case<\/span> <span class=\"n\">CustomMessageBoxResult<\/span><span class=\"p\">.<\/span><span class=\"n\">LeftButton<\/span><span class=\"p\">:<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"c1\">\/\/ Do something.<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">break<\/span><span class=\"p\">;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">case<\/span> <span class=\"n\">CustomMessageBoxResult<\/span><span class=\"p\">.<\/span><span class=\"n\">RightButton<\/span><span class=\"p\">:<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"c1\">\/\/ Do something.<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">break<\/span><span class=\"p\">;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">case<\/span> <span class=\"n\">CustomMessageBoxResult<\/span><span class=\"p\">.<\/span><span class=\"n\">None<\/span><span class=\"p\">:<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"c1\">\/\/ Do something.<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">break<\/span><span class=\"p\">;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">default<\/span><span class=\"p\">:<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">break<\/span><span class=\"p\">;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">};<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"n\">messageBox<\/span><span class=\"p\">.<\/span><span class=\"n\">Show<\/span><span class=\"p\">();<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><p>The title caption, message and buttons are configured, the <code>Dismissed()<\/code> event is assigned a handler and finally the Show() method is called to kick off the party.<\/p>\n<h2 id=\"taking-it-up-a-notch\">Taking It Up A Notch<\/h2>\n<p>That&rsquo;s all well and good but where is the real &ldquo;custom&rdquo; part of the CustomMessageBox? That comes in with the <code>Content<\/code> property where you insert your own content into the overall layout. You can define your extra content in either code-behind or as a XAML resource and then set it to the <code>Content<\/code> of the CustomMessageBox.<\/p>\n<p>The content area exists below where the Message is displayed yet right above the buttons.<\/p>\n<p>Let&rsquo;s say we want to recreate this dialog:<\/p>\n<p><a href=\"https:\/\/whiskeyandcode.com\/images\/image_12.png\"><img src=\"https:\/\/whiskeyandcode.com\/images\/image_thumb_12.png\" alt=\"image\" title=\"image\"><\/a><\/p>\n<h3 id=\"via-code-behind\">Via Code-Behind<\/h3>\n<p>One way to go about it would be to create all the custom content inline at the time of invocation:<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\"> 1\n<\/span><span class=\"lnt\"> 2\n<\/span><span class=\"lnt\"> 3\n<\/span><span class=\"lnt\"> 4\n<\/span><span class=\"lnt\"> 5\n<\/span><span class=\"lnt\"> 6\n<\/span><span class=\"lnt\"> 7\n<\/span><span class=\"lnt\"> 8\n<\/span><span class=\"lnt\"> 9\n<\/span><span class=\"lnt\">10\n<\/span><span class=\"lnt\">11\n<\/span><span class=\"lnt\">12\n<\/span><span class=\"lnt\">13\n<\/span><span class=\"lnt\">14\n<\/span><span class=\"lnt\">15\n<\/span><span class=\"lnt\">16\n<\/span><span class=\"lnt\">17\n<\/span><span class=\"lnt\">18\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-csharp\" data-lang=\"csharp\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">HyperlinkButton<\/span> <span class=\"n\">hyperlinkButton<\/span> <span class=\"p\">=<\/span> <span class=\"k\">new<\/span> <span class=\"n\">HyperlinkButton<\/span><span class=\"p\">()<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">Content<\/span> <span class=\"p\">=<\/span> <span class=\"s\">&#34;Privacy Statement&#34;<\/span><span class=\"p\">,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">Margin<\/span> <span class=\"p\">=<\/span> <span class=\"k\">new<\/span> <span class=\"n\">Thickness<\/span><span class=\"p\">(<\/span><span class=\"m\">0<\/span><span class=\"p\">,<\/span> <span class=\"m\">28<\/span><span class=\"p\">,<\/span> <span class=\"m\">0<\/span><span class=\"p\">,<\/span> <span class=\"m\">8<\/span><span class=\"p\">),<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">HorizontalAlignment<\/span> <span class=\"p\">=<\/span> <span class=\"n\">HorizontalAlignment<\/span><span class=\"p\">.<\/span><span class=\"n\">Left<\/span><span class=\"p\">,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">NavigateUri<\/span> <span class=\"p\">=<\/span> <span class=\"k\">new<\/span> <span class=\"n\">Uri<\/span><span class=\"p\">(<\/span><span class=\"s\">&#34;http:\/\/silverlight.codeplex.com\/&#34;<\/span><span class=\"p\">,<\/span> <span class=\"n\">UriKind<\/span><span class=\"p\">.<\/span><span class=\"n\">Absolute<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">};<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"n\">TiltEffect<\/span><span class=\"p\">.<\/span><span class=\"n\">SetIsTiltEnabled<\/span><span class=\"p\">(<\/span><span class=\"n\">hyperlinkButton<\/span><span class=\"p\">,<\/span> <span class=\"kc\">true<\/span><span class=\"p\">);<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"n\">CustomMessageBox<\/span> <span class=\"n\">messageBox<\/span> <span class=\"p\">=<\/span> <span class=\"k\">new<\/span> <span class=\"n\">CustomMessageBox<\/span><span class=\"p\">()<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">Caption<\/span> <span class=\"p\">=<\/span> <span class=\"s\">&#34;Allow this application to access and use your location?&#34;<\/span><span class=\"p\">,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">Message<\/span> <span class=\"p\">=<\/span> <span class=\"s\">&#34;Sharing this information helps us provide and improve the location-based services offered for this phone. We won&#39;t use the information to identify or contact you.&#34;<\/span><span class=\"p\">,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">Content<\/span> <span class=\"p\">=<\/span> <span class=\"n\">hyperlinkButton<\/span><span class=\"p\">,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">LeftButtonContent<\/span> <span class=\"p\">=<\/span> <span class=\"s\">&#34;allow&#34;<\/span><span class=\"p\">,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">RightButtonContent<\/span> <span class=\"p\">=<\/span> <span class=\"s\">&#34;cancel&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">};<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><p>The HyperlinkButton is created in code, tilt effect is set on the HyperlinkButton and to hook it together the HyperlinkButton is assigned to the Content property.<\/p>\n<h3 id=\"via-xaml\">Via XAML<\/h3>\n<p>Another approach is to create it as a DataTemplate in either the page or application resources and when you configure the dialog set the <strong>ContentTemplate<\/strong> property which may prove easier for more complicated templates.<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><span class=\"lnt\">2\n<\/span><span class=\"lnt\">3\n<\/span><span class=\"lnt\">4\n<\/span><span class=\"lnt\">5\n<\/span><span class=\"lnt\">6\n<\/span><span class=\"lnt\">7\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-xml\" data-lang=\"xml\"><span class=\"line\"><span class=\"cl\"><span class=\"nt\">&lt;DataTemplate<\/span> <span class=\"na\">x:Key=<\/span><span class=\"s\">&#34;HyperlinkContentTemplate&#34;<\/span><span class=\"nt\">&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;HyperlinkButton<\/span> <span class=\"na\">Content=<\/span><span class=\"s\">&#34;Privacy Statement&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">Margin=<\/span><span class=\"s\">&#34;0,28,0,8&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">HorizontalAlignment=<\/span><span class=\"s\">&#34;Left&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">NavigateUri=<\/span><span class=\"s\">&#34;http:\/\/silverlight.codeplex.com\/&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">TargetName=<\/span><span class=\"s\">&#34;_blank&#34;<\/span> <span class=\"nt\">\/&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nt\">&lt;\/DataTemplate&gt;<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><p>Now the code-behind looks like this:<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><span class=\"lnt\">2\n<\/span><span class=\"lnt\">3\n<\/span><span class=\"lnt\">4\n<\/span><span class=\"lnt\">5\n<\/span><span class=\"lnt\">6\n<\/span><span class=\"lnt\">7\n<\/span><span class=\"lnt\">8\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-csharp\" data-lang=\"csharp\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">CustomMessageBox<\/span> <span class=\"n\">messageBox<\/span> <span class=\"p\">=<\/span> <span class=\"k\">new<\/span> <span class=\"n\">CustomMessageBox<\/span><span class=\"p\">()<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">Caption<\/span> <span class=\"p\">=<\/span> <span class=\"s\">&#34;Allow this application to access and use your location?&#34;<\/span><span class=\"p\">,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">Message<\/span> <span class=\"p\">=<\/span> <span class=\"s\">&#34;Sharing this information helps us provide and improve the location-based services offered for this phone. We won&#39;t use the information to identify or contact you.&#34;<\/span><span class=\"p\">,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">ContentTemplate<\/span> <span class=\"p\">=<\/span> <span class=\"p\">(<\/span><span class=\"n\">DataTemplate<\/span><span class=\"p\">)<\/span><span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"n\">Resources<\/span><span class=\"p\">[<\/span><span class=\"s\">&#34;HyperlinkContentTemplate&#34;<\/span><span class=\"p\">],<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">LeftButtonContent<\/span> <span class=\"p\">=<\/span> <span class=\"s\">&#34;allow&#34;<\/span><span class=\"p\">,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">RightButtonContent<\/span> <span class=\"p\">=<\/span> <span class=\"s\">&#34;cancel&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">};<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><h2 id=\"more-samples\">More Samples<\/h2>\n<p>You can find more examples, including the source to the &ldquo;What Can I Say?&rdquo; screenshot I showed above, in the Toolkit Samples project which you can either get via <a href=\"http:\/\/silverlight.codeplex.com\/SourceControl\/changeset\/view\/79895#\">downloading the latest source<\/a> or looking at it <a href=\"http:\/\/silverlight.codeplex.com\/SourceControl\/changeset\/view\/79895#1899866\">directly on CodePlex<\/a>.<\/p>\n<p>As always feedback is appreciated via either comments here or on <a href=\"http:\/\/silverlight.codeplex.com\/\">CodePlex<\/a>. We review each piece of feedback and we do get to them, if sometimes a little later than we&rsquo;d like. Our goal is to make it so you can focus on writing your application vs. having to recreate the UI you see on the phone.<\/p>","category":{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/categories\/windows-phone\/","term":"Windows Phone","label":"Windows Phone"}}},{"title":"C# and Sublime Text 2 PROTIPS","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/c-and-sublime-text-2-protips\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/c-and-sublime-text-2-protips\/","updated":"2026-10-18T02:41:51+00:00","published":"2012-05-09T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"Given how powerful, fast and easy Sublime Text 2 is I find myself editing a great deal of my C# &amp; XAML code in it and then switching to Visual Studio to launch the application. Along those lines I&rsquo;ve picked up a few C# Sublime tips.","content":"<p>Given how powerful, fast and easy <a href=\"http:\/\/www.sublimetext.com\/blog\/articles\/sublime-text-2-beta\">Sublime Text 2<\/a> is I find myself editing a great deal of my C# &amp; XAML code in it and then switching to Visual Studio to launch the application. Along those lines I&rsquo;ve picked up a few C# Sublime tips.<\/p>\n<h2 id=\"1-update-your-c-bundle\">1. Update Your C# Bundle<\/h2>\n<p>The syntax and snippet bundle that comes with Sublime is a bit out of date and more importantly it doesn&rsquo;t correctly identify methods so you are missing a huge chunk of the power of the Ctrl+R &ldquo;jump to method&rdquo; hotkey. Grab an <a href=\"https:\/\/github.com\/wintermi\/csharp-tmbundle\">updated bundle<\/a> over on GitHub.<\/p>\n<p>This is a TextMate bundle so you&rsquo;ll need to do some slicing and dicing to get it to play nicely with Sublime, most notably move the files in the Syntax and Preferences folders into the root of the C# package. If you need more details than that just hit me up and I&rsquo;ll add the step-by-step.<\/p>\n<h2 id=\"2-add-msbuild-as-a-build-system\">2. Add msbuild as a Build System<\/h2>\n<p>I do a build sometimes as a quick and dirty syntax &amp; sanity check and it&rsquo;s nice to be able to trigger it from Sublime vs. having to swap back to VS. I whipped this up and dropped it into my <code>\/Sublime Text 2\/Packages\/User<\/code> folder as <code>msbuild.sublime-build<\/code>.<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><span class=\"lnt\">2\n<\/span><span class=\"lnt\">3\n<\/span><span class=\"lnt\">4\n<\/span><span class=\"lnt\">5\n<\/span><span class=\"lnt\">6\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-json\" data-lang=\"json\"><span class=\"line\"><span class=\"cl\"><span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&#34;cmd&#34;<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span><span class=\"s2\">&#34;msbuild&#34;<\/span><span class=\"p\">],<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&#34;path&#34;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&#34;C:\\\\Windows\\\\Microsoft.NET\\\\Framework\\\\v4.0.30319&#34;<\/span><span class=\"p\">,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&#34;working_dir&#34;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&#34;${project_path:${folder}}&#34;<\/span><span class=\"p\">,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&#34;file_regex&#34;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&#34;^ (.*)\\\\(([0-9]*),([0-9]*)&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><p>F7 to compile, F4 to jump to each compiler error (I know, I know, you don&rsquo;t have bugs but that other coder&hellip;).<\/p>\n<p>I&rsquo;m using a hard-coded msbuild location, that&rsquo;s stinky and a better solution would be to use environment variables and such but&hellip; Works On My Two Machines That Are Sync&rsquo;d With Dropbox.<\/p>\n<p>If you have a Sublime project open (which is really a collection folders that act as a scope for searches, I resisted them foreva but am now an addict) this will call msbuild at the project root, otherwise it&rsquo;ll look in the same folder as the file you&rsquo;re editing.<\/p>\n<h2 id=\"3-create-some-snippets\">3. Create Some Snippets<\/h2>\n<p>Visual Studio 2010 ships with some awesome and must-have C# snippets. I haven&rsquo;t tried to recreate them all in Sublime (I really do like VS you know) but there are some tricks Sublime can do that Visual Studio just can&rsquo;t. One nice one is being able to whip up some regex magic on replacements which comes in handy for things like changing the casing between private and public variables. An example will work better:<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\"> 1\n<\/span><span class=\"lnt\"> 2\n<\/span><span class=\"lnt\"> 3\n<\/span><span class=\"lnt\"> 4\n<\/span><span class=\"lnt\"> 5\n<\/span><span class=\"lnt\"> 6\n<\/span><span class=\"lnt\"> 7\n<\/span><span class=\"lnt\"> 8\n<\/span><span class=\"lnt\"> 9\n<\/span><span class=\"lnt\">10\n<\/span><span class=\"lnt\">11\n<\/span><span class=\"lnt\">12\n<\/span><span class=\"lnt\">13\n<\/span><span class=\"lnt\">14\n<\/span><span class=\"lnt\">15\n<\/span><span class=\"lnt\">16\n<\/span><span class=\"lnt\">17\n<\/span><span class=\"lnt\">18\n<\/span><span class=\"lnt\">19\n<\/span><span class=\"lnt\">20\n<\/span><span class=\"lnt\">21\n<\/span><span class=\"lnt\">22\n<\/span><span class=\"lnt\">23\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-xml\" data-lang=\"xml\"><span class=\"line\"><span class=\"cl\"><span class=\"nt\">&lt;snippet&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;tabTrigger&gt;<\/span>propc<span class=\"nt\">&lt;\/tabTrigger&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;content&gt;<\/span><span class=\"cp\">&lt;![CDATA[\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"cp\">private ${1:string} _${2};\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"cp\">public ${1} ${2\/.\/\\u$0\/}\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"cp\">{\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"cp\"> get\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"cp\"> {\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"cp\"> return _${2};\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"cp\"> }\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"cp\"> set\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"cp\"> {\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"cp\"> if (_${2} != value)\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"cp\"> {\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"cp\"> _${2} = value;\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"cp\"> OnPropertyChanged(&#34;${2\/.\/\\u$0\/}&#34;);\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"cp\"> }\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"cp\"> }\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"cp\">}\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"cp\">]]&gt;<\/span><span class=\"nt\">&lt;\/content&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;scope&gt;<\/span>source.cs<span class=\"nt\">&lt;\/scope&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;description&gt;<\/span>Property that raises PropertyChanged<span class=\"nt\">&lt;\/description&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nt\">&lt;\/snippet&gt;<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><p>Also VS doesn&rsquo;t support XAML snippets and that about makes me cry every time I have to type yet another angle bracket so go ahead and create some tasty XAML snippets. I dropped a few <a href=\"https:\/\/whiskeyandcode.com\/downloads\/XAML.zip\">into a zip here<\/a>.<\/p>\n<p>Have any other protips for working with C# or XAML inside of Sublime? I&rsquo;d love to hear them and if you have any questions about my workflow don&rsquo;t be shy.<\/p>"},{"title":"How to make the Windows Phone Toolkit ToggleSwitch Header wrap","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/how-to-make-the-windows-phone-toolkit-toggleswitch-header-wrap\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/how-to-make-the-windows-phone-toolkit-toggleswitch-header-wrap\/","updated":"2026-10-18T02:41:51+00:00","published":"2012-04-28T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"I&rsquo;m going through the Windows Phone Toolkit bugs fixing some of the low hanging fruit and came across this bug where a ToggleSwitch with a long header is clipped. The proper Metro behavior is that it should wrap which is easy enough to do on a TextBlock.","content":"<p>I&rsquo;m going through the <a href=\"http:\/\/silverlight.codeplex.com\/\">Windows Phone Toolkit<\/a> bugs fixing some of the low hanging fruit and came across <a href=\"http:\/\/silverlight.codeplex.com\/workitem\/10612\">this bug<\/a> where a ToggleSwitch with a long header is clipped. The proper Metro behavior is that it should wrap which is easy enough to do on a TextBlock. The rub though is that the Header is represented by a ContentControl, not a TextBlock.<\/p>\n<p>ContentControl makes it easy to put whatever you&rsquo;d like into the Header; images, other controls, buttons, etc. and is the standard Silverlight way of representing content. This is great for an open-ended environment like the Silverlight plug-in where each app has it&rsquo;s own UI but on the phone you want as close to the Metro UI as you can get. In a perfect world (or just one with a time machine) we would have made Header a TextBlock with wrapping turned on but, well, we didn&rsquo;t. We&rsquo;re still debating if we should just make the switch and deal with the fall out but until then here is a super simple way to ensure your Header text wraps when it needs to:<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\"> 1\n<\/span><span class=\"lnt\"> 2\n<\/span><span class=\"lnt\"> 3\n<\/span><span class=\"lnt\"> 4\n<\/span><span class=\"lnt\"> 5\n<\/span><span class=\"lnt\"> 6\n<\/span><span class=\"lnt\"> 7\n<\/span><span class=\"lnt\"> 8\n<\/span><span class=\"lnt\"> 9\n<\/span><span class=\"lnt\">10\n<\/span><span class=\"lnt\">11\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-xml\" data-lang=\"xml\"><span class=\"line\"><span class=\"cl\"><span class=\"nt\">&lt;toolkit:ToggleSwitch<\/span> <span class=\"na\">Header=<\/span><span class=\"s\">&#34;This is an example of a really long description label for localization&#34;<\/span><span class=\"nt\">&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;toolkit:ToggleSwitch.HeaderTemplate&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;DataTemplate&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;TextBlock<\/span> <span class=\"na\">FontFamily=<\/span><span class=\"s\">&#34;{StaticResource PhoneFontFamilyNormal}&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">FontSize=<\/span><span class=\"s\">&#34;{StaticResource PhoneFontSizeNormal}&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">Foreground=<\/span><span class=\"s\">&#34;{StaticResource PhoneSubtleBrush}&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">TextWrapping=<\/span><span class=\"s\">&#34;Wrap&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">Text=<\/span><span class=\"s\">&#34;{Binding}&#34;<\/span> <span class=\"nt\">\/&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;\/DataTemplate&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;\/toolkit:ToggleSwitch.HeaderTemplate&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nt\">&lt;\/toolkit:ToggleSwitch&gt;<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><p>Which gets you:<\/p>\n<p><a href=\"https:\/\/whiskeyandcode.com\/images\/image_9.png\"><img src=\"https:\/\/whiskeyandcode.com\/images\/image_thumb_9.png\" alt=\"image\" title=\"image\"><\/a><\/p>\n<p>If you&rsquo;re going to do any type of localization I recommend you make this change to all your ToggleSwitch controls.<\/p>","category":{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/categories\/windows-phone\/","term":"Windows Phone","label":"Windows Phone"}}},{"title":"Unable to Clear East Asian Text from a TextBox in Windows Phone (or always clear your TextBox focus)","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/unable-to-clear-east-asian-text-from-a-textbox-in-windows-phone-or-always-clear-your-textbox-focus\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/unable-to-clear-east-asian-text-from-a-textbox-in-windows-phone-or-always-clear-your-textbox-focus\/","updated":"2026-10-18T02:41:51+00:00","published":"2012-04-24T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"We&rsquo;ve received several reports of apps that don&rsquo;t clear out their text even though the app author is setting the Text property to an empty string. I did a little poking and it&rsquo;s due to a combination of the application bar and IME.","content":"<p>We&rsquo;ve received several reports of apps that don&rsquo;t clear out their text even though the app author is setting the Text property to an empty string. I did a little poking and it&rsquo;s due to a combination of the application bar and IME. The onscreen keyboard (SIP) enters a composition mode when working with East Asian languages that allows for quickly entering complex words and phrases and it ends once the SIP is dismissed. If the text is modified programmatically while it&rsquo;s in this mode it&rsquo;ll behave unpredictably, the most obvious issue being that it doesn&rsquo;t update to reflect the text you&rsquo;ve set in your code behind.<\/p>\n<p>You can tell if a TextBox is in this mode by the underline underneath the current character you&rsquo;re editing:<\/p>\n<p><a href=\"https:\/\/whiskeyandcode.com\/images\/image_8.png\"><img src=\"https:\/\/whiskeyandcode.com\/images\/image_thumb_8.png\" alt=\"image\" title=\"image\"><\/a><\/p>\n<p>Because the ApplicationBar isn&rsquo;t drawn or managed by Silverlight focus won&rsquo;t properly be taken away from the currently active control (the TextBox) and any attempt to change the text via the Text property will put the TextBox into the state I mentioned above. The most common way this happens is performing some action on the text such as sending a message and then attempting to clear it out.<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><span class=\"lnt\">2\n<\/span><span class=\"lnt\">3\n<\/span><span class=\"lnt\">4\n<\/span><span class=\"lnt\">5\n<\/span><span class=\"lnt\">6\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-csharp\" data-lang=\"csharp\"><span class=\"line\"><span class=\"cl\"><span class=\"kd\">private<\/span> <span class=\"k\">void<\/span> <span class=\"n\">ApplicationBarIconButton_Click<\/span><span class=\"p\">(<\/span><span class=\"kt\">object<\/span> <span class=\"n\">sender<\/span><span class=\"p\">,<\/span> <span class=\"n\">EventArgs<\/span> <span class=\"n\">e<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">ChatUpFriend<\/span><span class=\"p\">(<\/span><span class=\"n\">MessageTextBox<\/span><span class=\"p\">.<\/span><span class=\"n\">Text<\/span><span class=\"p\">);<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">MessageTextBox<\/span><span class=\"p\">.<\/span><span class=\"n\">Text<\/span> <span class=\"p\">=<\/span> <span class=\"s\">&#34;&#34;<\/span><span class=\"p\">;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><p>Luckily the work around is easy, force the SIP to be dismissed before clearing the Text property and everything will work as expected. The most common\/easiest way is to set focus to the page itself:<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\"> 1\n<\/span><span class=\"lnt\"> 2\n<\/span><span class=\"lnt\"> 3\n<\/span><span class=\"lnt\"> 4\n<\/span><span class=\"lnt\"> 5\n<\/span><span class=\"lnt\"> 6\n<\/span><span class=\"lnt\"> 7\n<\/span><span class=\"lnt\"> 8\n<\/span><span class=\"lnt\"> 9\n<\/span><span class=\"lnt\">10\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-csharp\" data-lang=\"csharp\"><span class=\"line\"><span class=\"cl\"><span class=\"kd\">private<\/span> <span class=\"k\">void<\/span> <span class=\"n\">ApplicationBarIconButton_Click<\/span><span class=\"p\">(<\/span><span class=\"kt\">object<\/span> <span class=\"n\">sender<\/span><span class=\"p\">,<\/span> <span class=\"n\">EventArgs<\/span> <span class=\"n\">e<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"c1\">\/\/ Set focus to the page ensuring all TextBox controls are properly committed<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"c1\">\/\/ and that the IME session has been correctly closed.<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"n\">Focus<\/span><span class=\"p\">();<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">ChatUpFriend<\/span><span class=\"p\">(<\/span><span class=\"n\">MessageTextBox<\/span><span class=\"p\">.<\/span><span class=\"n\">Text<\/span><span class=\"p\">);<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">MessageTextBox<\/span><span class=\"p\">.<\/span><span class=\"n\">Text<\/span> <span class=\"p\">=<\/span> <span class=\"s\">&#34;&#34;<\/span><span class=\"p\">;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><p>I recommend putting this code anywhere you&rsquo;re clearing out a TextBox as you never know what language your users will be typing in.<\/p>","category":{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/categories\/windows-phone\/","term":"Windows Phone","label":"Windows Phone"}}},{"title":"Sublime Text: Fashion and Form Text Editing","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/sublime-text-fashion-and-form-text-editing\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/sublime-text-fashion-and-form-text-editing\/","updated":"2026-10-18T02:41:51+00:00","published":"2012-02-23T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"I have an odd love of text editors, though considering I love to code perhaps it&rsquo;s not that odd at all. I&rsquo;ve gone through quite a few over the years, I was a huge TextPad fan for a long time and I still pull it up now and then but then I saw a bunch of screen shots of TextMate on Mac and realized the bar had been reset.","content":"<p>I have an odd love of text editors, though considering I love to code perhaps it&rsquo;s not that odd at all. I&rsquo;ve gone through quite a few over the years, I was a huge <a href=\"http:\/\/www.textpad.com\/\">TextPad<\/a> fan for a long time and I still pull it up now and then but then I saw a bunch of screen shots of <a href=\"http:\/\/macromates.com\/\">TextMate<\/a> on Mac and realized the bar had been reset. From there I was on a search for an editor that was both smart AND sexy and I went through a bunch of editors looking for &ldquo;the right one&rdquo;, from <a href=\"http:\/\/www.e-texteditor.com\/\">E Text Editor<\/a> (nice but made me install cygwin for full power) to <a href=\"http:\/\/inotai.com\/intype\/\">Intype<\/a> (beautiful and had a great start but languished for a year though I hear they&rsquo;re working again in earnest) and finally to <a href=\"http:\/\/www.sublimetext.com\/\">Sublime Text 2<\/a> which is what this post is all about.<\/p>\n<p>I&rsquo;ve been using Sublime for about a year, since roughly Build 2020 of Subliime Text 2 and the project just keeps getting better and better. I highly recommend you grab the <a href=\"http:\/\/www.sublimetext.com\/2\">development builds<\/a> and install the latest as they come down the pipe. Sublime is even nice enough to let you know when there are new builds available.<\/p>\n<p><img src=\"https:\/\/whiskeyandcode.com\/images\/SublimeTextMain.png\" alt=\"Sublime Text Main\" title=\"Sublime Text Main\"><\/p>\n<h2 id=\"why-use-anything-besides-visual-studio\">Why Use Anything Besides Visual Studio?<\/h2>\n<p>Why indeed since I sling a lot of C# during my day? First is the <strong>speed<\/strong>, VS does a lot for you and sometimes you pay that cost and when I just want to work with text I reach for Sublime.<\/p>\n<p><strong>Snippet support<\/strong>. It&rsquo;s super fast to create new snippets as well as build in some intelligence via regex. It&rsquo;s probably just me but creating new snippets in VS always seems like a heavy process but it&rsquo;s so easy with Sublime I find myself creating them for any block code more than two lines long. I have one cool snippet for creating new properties with a backing private variable and it takes care of creating both the public and private variables and correctly casing each one, something I don&rsquo;t believe you can do in VS.<\/p>\n<p><strong>Multiple Selection<\/strong>. This is a must have for any modern editor and it&rsquo;s best if you see it in action but roughly if you Ctrl select multiple words and then start typing all of the selected items will start updating. Great for quickly changing types such swapping from a Grid to StackPanel in XAML.<\/p>\n<p><strong>Auto-Complete.<\/strong> You won&rsquo;t lose any of your fancy auto-complete either, Sublime uses the current syntax bundle to parse your files and determine what should be considered key words.<\/p>\n<p><strong>Jump To.<\/strong> Ctrl+P to jump to any file in your project. Ctrl+, to jump to any symbol. Ctrl+Shift+P to look at all available commands and snippets. Awesome and super fast.<\/p>\n<p><strong>Project Management.<\/strong> Drag &amp; drop a folder into Sublime and now all your jump to features become much more powerful as you can move between files in your project.<\/p>\n<p><strong>And so much more.<\/strong> Seriously. Support for TextMate bundles, great color themes, code-folding, macro support, margin guides, a ton of extensibility, active forums, weekly updates, etc.<\/p>\n<h2 id=\"pro-tips--downloads\">Pro-Tips &amp; Downloads<\/h2>\n<ol>\n<li>\n<p>Keep your Sublime configuration in sync between computers with DropBox (see <a href=\"http:\/\/juhap.iki.fi\/misc\/using-dropbox-to-sync-sublime-text-settings-across-windows-computers\/\">Using Dropbox to sync Sublime Text settings across Windows computers<\/a>).<\/p>\n<\/li>\n<li>\n<p>If you use VS don&rsquo;t forget to setup Sublime as an External Tool. I&rsquo;m constantly moving between VS &amp; Sublime and since both programs are great about picking up changes this is a great combo.<\/p>\n<\/li>\n<li>\n<p>Install <a href=\"http:\/\/wbond.net\/sublime_packages\/package_control\">Sublime Package Control<\/a>. Think of it as gems or NuGet for Sublime. After you install it browse some of the cool packages available. My current favs are:<\/p>\n<ul>\n<li>Sublime TFS - check out, commit &amp; via history for files under TFS control.<\/li>\n<li>sublime-github - A great list of commands for managing your Gists from Github.<\/li>\n<li>SublimeAStyleFormatter - A pretty code formatter for C#.<\/li>\n<li>Theme - Soda - A nice dark theme for the entire editor itself.<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>Check out what others are saying (<a href=\"http:\/\/wekeroad.com\/2012\/01\/13\/sublime-text-the-text-editor-youll-fall-in-love-with-3\/\">Rob Conery<\/a>)<\/p>\n<\/li>\n<li>\n<p>Check out this great list of pro-tips (<a href=\"http:\/\/net.tutsplus.com\/tutorials\/tools-and-tips\/sublime-text-2-tips-and-tricks\/\">Sublime Text 2 Tips and Tricks (Updated)<\/a>)<\/p>\n<\/li>\n<li>\n<p>If you edit in XAML here is a XAML bundle I ported (it&rsquo;s basically a copy of the XML bundle and a porting of some of the TextMate snippets from the <a href=\"http:\/\/visitmix.com\/labs\/gestalt\/\">Microsoft Gestalt project<\/a>).<\/p>\n<ul>\n<li><a href=\"https:\/\/whiskeyandcode.com\/downloads\/XAML.zip\">XAML Sublime Bundle<\/a><\/li>\n<\/ul>\n<\/li>\n<\/ol>"},{"title":"Using RestSharp with AgFx in your Windows Phone app","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/using-restsharp-with-agfx-in-your-windows-phone-app\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/using-restsharp-with-agfx-in-your-windows-phone-app\/","updated":"2026-10-18T02:41:51+00:00","published":"2012-02-15T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"I&rsquo;m using the excellent REST library RestSharp for all my REST and OAuth calls. I&rsquo;m also using the amazing data caching framework AgFx written by Shawn Burke which handles caching your web requests, something that goes from a nice to have to critical when writing high performance Windows Phone apps.","content":"<p>I&rsquo;m using the excellent REST library <a href=\"http:\/\/restsharp.org\">RestSharp<\/a> for all my REST and OAuth calls. I&rsquo;m also using the amazing data caching framework <a href=\"http:\/\/agfx.codeplex.com\/\">AgFx<\/a> written by Shawn Burke which handles caching your web requests, something that goes from a nice to have to critical when writing high performance Windows Phone apps.<\/p>\n<p>Out of the box AgFx handles all your requests so it can do it&rsquo;s caching thing, getting in the front of each request to determine if it should give you a cached version instead of hitting the web, if it should invalidate the cache, if it should give you a cached version and then make a live request, etc. This is how you want it but sometimes you want more control over how those live requests are made. In my case I&rsquo;m using OAuth and requesting protected resources that require OAuth access tokens and RestSharp has some very nice methods for both authenticating and making those pesky protected calls. The question is how to slip RestSharp into the middle of the AgFx mechanism?<\/p>\n<h2 id=\"agfx-out-of-the-box\">AgFx Out of the Box<\/h2>\n<p>Your basic AgFx call looks like this:<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-csharp\" data-lang=\"csharp\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">ZipCodeVm<\/span> <span class=\"n\">viewModel<\/span> <span class=\"p\">=<\/span> <span class=\"n\">DataManager<\/span><span class=\"p\">.<\/span><span class=\"n\">Current<\/span><span class=\"p\">.<\/span><span class=\"n\">Load<\/span><span class=\"p\">&lt;<\/span><span class=\"n\">ZipCodeVm<\/span><span class=\"p\">&gt;(<\/span><span class=\"n\">txtZipCode<\/span><span class=\"p\">.<\/span><span class=\"n\">Text<\/span><span class=\"p\">);<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><p>Which eventually executes code like this (which you the developer has written):<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><span class=\"lnt\">2\n<\/span><span class=\"lnt\">3\n<\/span><span class=\"lnt\">4\n<\/span><span class=\"lnt\">5\n<\/span><span class=\"lnt\">6\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-csharp\" data-lang=\"csharp\"><span class=\"line\"><span class=\"cl\"><span class=\"kd\">public<\/span> <span class=\"n\">LoadRequest<\/span> <span class=\"n\">GetLoadRequest<\/span><span class=\"p\">(<\/span><span class=\"n\">ZipCodeLoadContext<\/span> <span class=\"n\">loadContext<\/span><span class=\"p\">,<\/span> <span class=\"n\">Type<\/span> <span class=\"n\">objectType<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"c1\">\/\/ build the URI, return a WebLoadRequest.<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"kt\">string<\/span> <span class=\"n\">uri<\/span> <span class=\"p\">=<\/span> <span class=\"n\">String<\/span><span class=\"p\">.<\/span><span class=\"n\">Format<\/span><span class=\"p\">(<\/span><span class=\"n\">ZipCodeUriFormat<\/span><span class=\"p\">,<\/span> <span class=\"n\">loadContext<\/span><span class=\"p\">.<\/span><span class=\"n\">ZipCode<\/span><span class=\"p\">);<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">return<\/span> <span class=\"k\">new<\/span> <span class=\"n\">WebLoadRequest<\/span><span class=\"p\">(<\/span><span class=\"n\">loadContext<\/span><span class=\"p\">,<\/span> <span class=\"k\">new<\/span> <span class=\"n\">Uri<\/span><span class=\"p\">(<\/span><span class=\"n\">uri<\/span><span class=\"p\">));<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><p>AgFx will call GetLoadRequest() to get a LoadRequest which it&rsquo;ll use when it needs to fetch live data. This example is using the default WebLoadRequest which uses HttpWebRequest under the covers to fetch the data but as long as you return an object that descends from LoadRequest you can use whatever requesting mechanism you like.<\/p>\n<h2 id=\"restsharploadrequest\">RestSharpLoadRequest<\/h2>\n<p>That&rsquo;s where RestSharp comes in. Instead of hand-crafting HTTP requests including hand-crafting headers and building POST payloads I&rsquo;m going to let RestSharp do the heavy lifting by creating a custom RestSharpLoadRequest. It&rsquo;s based heavily on the WebLoadRequest in AgFX, right down to the comments and took all of 15 minutes to code up. It&rsquo;s not that exciting of a class but you can download it and view it on github as a gist:<\/p>\n<p><a href=\"https:\/\/gist.github.com\/1832559\">An AgFx LoadRequest that uses RestSharp to make the actual request, supports passing in OAuth tokens<\/a><\/p>\n<p><a href=\"https:\/\/gist.github.com\/gists\/1832559\/download\">Download it<\/a> and drop it into your application as is (well, I&rsquo;d probably change the namespace to something more appropriate). Sorry about it being a tar.gz file, maybe I&rsquo;ll ping <a href=\"http:\/\/haacked.com\/\">Phil Haack<\/a> now that he works there to offer up .zips for gists as well.<\/p>\n<p><strong>WOW<\/strong>, sorry folks, I didn&rsquo;t realize I&rsquo;d created the Gist as private, if you tried to view it before you should have better luck now.<\/p>\n<h2 id=\"restsharploadrequest-in-action\">RestSharpLoadRequest in Action<\/h2>\n<p>I&rsquo;m going straight to a meaty example where I create a few parameters to throw on the URL and pass in all my OAuth token goodness:<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\"> 1\n<\/span><span class=\"lnt\"> 2\n<\/span><span class=\"lnt\"> 3\n<\/span><span class=\"lnt\"> 4\n<\/span><span class=\"lnt\"> 5\n<\/span><span class=\"lnt\"> 6\n<\/span><span class=\"lnt\"> 7\n<\/span><span class=\"lnt\"> 8\n<\/span><span class=\"lnt\"> 9\n<\/span><span class=\"lnt\">10\n<\/span><span class=\"lnt\">11\n<\/span><span class=\"lnt\">12\n<\/span><span class=\"lnt\">13\n<\/span><span class=\"lnt\">14\n<\/span><span class=\"lnt\">15\n<\/span><span class=\"lnt\">16\n<\/span><span class=\"lnt\">17\n<\/span><span class=\"lnt\">18\n<\/span><span class=\"lnt\">19\n<\/span><span class=\"lnt\">20\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-csharp\" data-lang=\"csharp\"><span class=\"line\"><span class=\"cl\"><span class=\"kd\">public<\/span> <span class=\"n\">LoadRequest<\/span> <span class=\"n\">GetLoadRequest<\/span><span class=\"p\">(<\/span><span class=\"n\">ShelfLoadContext<\/span> <span class=\"n\">loadContext<\/span><span class=\"p\">,<\/span> <span class=\"n\">Type<\/span> <span class=\"n\">objectType<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"kt\">var<\/span> <span class=\"n\">resource<\/span> <span class=\"p\">=<\/span> <span class=\"n\">BuildResource<\/span><span class=\"p\">(<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"s\">&#34;review\/list.xml&#34;<\/span><span class=\"p\">,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">new<\/span> <span class=\"n\">Dictionary<\/span><span class=\"p\">&lt;<\/span><span class=\"kt\">string<\/span> <span class=\"kt\">string<\/span> <span class=\"p\">,&gt;()<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">{<\/span><span class=\"s\">&#34;v&#34;<\/span><span class=\"p\">,<\/span> <span class=\"s\">&#34;2&#34;<\/span><span class=\"p\">},<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">{<\/span><span class=\"s\">&#34;id&#34;<\/span><span class=\"p\">,<\/span> <span class=\"n\">loadContext<\/span><span class=\"p\">.<\/span><span class=\"n\">UserId<\/span><span class=\"p\">},<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">{<\/span><span class=\"s\">&#34;page&#34;<\/span><span class=\"p\">,<\/span> <span class=\"n\">loadContext<\/span><span class=\"p\">.<\/span><span class=\"n\">Page<\/span><span class=\"p\">.<\/span><span class=\"n\">ToString<\/span><span class=\"p\">()},<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">{<\/span><span class=\"s\">&#34;shelf&#34;<\/span><span class=\"p\">,<\/span> <span class=\"n\">loadContext<\/span><span class=\"p\">.<\/span><span class=\"n\">Shelf<\/span><span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">});<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">return<\/span> <span class=\"k\">new<\/span> <span class=\"n\">RestSharpLoadRequest<\/span><span class=\"p\">(<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">loadContext<\/span><span class=\"p\">,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">resource<\/span><span class=\"p\">,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">Client<\/span><span class=\"p\">.<\/span><span class=\"n\">Current<\/span><span class=\"p\">.<\/span><span class=\"n\">ConsumerKey<\/span><span class=\"p\">,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">Client<\/span><span class=\"p\">.<\/span><span class=\"n\">Current<\/span><span class=\"p\">.<\/span><span class=\"n\">ConsumerSecret<\/span><span class=\"p\">,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">Client<\/span><span class=\"p\">.<\/span><span class=\"n\">Current<\/span><span class=\"p\">.<\/span><span class=\"n\">AccessToken<\/span><span class=\"p\">,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">Client<\/span><span class=\"p\">.<\/span><span class=\"n\">Current<\/span><span class=\"p\">.<\/span><span class=\"n\">AccessTokenSecret<\/span><span class=\"p\">);<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><p>Don&rsquo;t worry about the BuildResource call, that&rsquo;s simply building up your REST API end-point (aka &ldquo;resource&rdquo;). The only difference from the standard usage of AgFx is instead of a WebLoadRequest I&rsquo;m using RestSharpLoadRequest.<\/p>\n<p>And there you have it, now you can lean on RestSharp inside of the AgFx framework. Also If you&rsquo;re using <a href=\"https:\/\/github.com\/danielcrenna\/hammock\">Hammock<\/a> as your REST library as choice it should take all of 15 minutes to whip up a HammockLoadRequest following the same basic principles.<\/p>\n<p><strong>UPDATE (02.14.2010):<\/strong> The way I was handing parameters above was just plain weird, the RestRequest object that I&rsquo;m using inside of RestSharpLoadRequest already has robust AddParameter() logic so I exposed it. The above code now looks like this:<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\"> 1\n<\/span><span class=\"lnt\"> 2\n<\/span><span class=\"lnt\"> 3\n<\/span><span class=\"lnt\"> 4\n<\/span><span class=\"lnt\"> 5\n<\/span><span class=\"lnt\"> 6\n<\/span><span class=\"lnt\"> 7\n<\/span><span class=\"lnt\"> 8\n<\/span><span class=\"lnt\"> 9\n<\/span><span class=\"lnt\">10\n<\/span><span class=\"lnt\">11\n<\/span><span class=\"lnt\">12\n<\/span><span class=\"lnt\">13\n<\/span><span class=\"lnt\">14\n<\/span><span class=\"lnt\">15\n<\/span><span class=\"lnt\">16\n<\/span><span class=\"lnt\">17\n<\/span><span class=\"lnt\">18\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-csharp\" data-lang=\"csharp\"><span class=\"line\"><span class=\"cl\"><span class=\"kd\">public<\/span> <span class=\"kd\">override<\/span> <span class=\"n\">LoadRequest<\/span> <span class=\"n\">GetLoadRequest<\/span><span class=\"p\">(<\/span><span class=\"n\">ShelfLoadContext<\/span> <span class=\"n\">loadContext<\/span><span class=\"p\">,<\/span> <span class=\"n\">Type<\/span> <span class=\"n\">objectType<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"kt\">var<\/span> <span class=\"n\">request<\/span> <span class=\"p\">=<\/span> <span class=\"k\">new<\/span> <span class=\"n\">RestSharpLoadRequest<\/span><span class=\"p\">(<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">loadContext<\/span><span class=\"p\">,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">GoodReadsClient<\/span><span class=\"p\">.<\/span><span class=\"n\">Current<\/span><span class=\"p\">.<\/span><span class=\"n\">BuildResource<\/span><span class=\"p\">(<\/span><span class=\"s\">&#34;review\/list.xml&#34;<\/span><span class=\"p\">),<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">GoodReadsClient<\/span><span class=\"p\">.<\/span><span class=\"n\">Current<\/span><span class=\"p\">.<\/span><span class=\"n\">ConsumerKey<\/span><span class=\"p\">,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">GoodReadsClient<\/span><span class=\"p\">.<\/span><span class=\"n\">Current<\/span><span class=\"p\">.<\/span><span class=\"n\">ConsumerSecret<\/span><span class=\"p\">,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">GoodReadsClient<\/span><span class=\"p\">.<\/span><span class=\"n\">Current<\/span><span class=\"p\">.<\/span><span class=\"n\">AccessToken<\/span><span class=\"p\">,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">GoodReadsClient<\/span><span class=\"p\">.<\/span><span class=\"n\">Current<\/span><span class=\"p\">.<\/span><span class=\"n\">AccessTokenSecret<\/span><span class=\"p\">);<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">request<\/span><span class=\"p\">.<\/span><span class=\"n\">AddParameter<\/span><span class=\"p\">(<\/span><span class=\"s\">&#34;key&#34;<\/span><span class=\"p\">,<\/span> <span class=\"n\">GoodReadsClient<\/span><span class=\"p\">.<\/span><span class=\"n\">Current<\/span><span class=\"p\">.<\/span><span class=\"n\">ConsumerKey<\/span><span class=\"p\">);<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">request<\/span><span class=\"p\">.<\/span><span class=\"n\">AddParameter<\/span><span class=\"p\">(<\/span><span class=\"s\">&#34;shelf&#34;<\/span><span class=\"p\">,<\/span> <span class=\"n\">loadContext<\/span><span class=\"p\">.<\/span><span class=\"n\">Shelf<\/span><span class=\"p\">);<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">request<\/span><span class=\"p\">.<\/span><span class=\"n\">AddParameter<\/span><span class=\"p\">(<\/span><span class=\"s\">&#34;v&#34;<\/span><span class=\"p\">,<\/span> <span class=\"s\">&#34;2&#34;<\/span><span class=\"p\">);<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">request<\/span><span class=\"p\">.<\/span><span class=\"n\">AddParameter<\/span><span class=\"p\">(<\/span><span class=\"s\">&#34;id&#34;<\/span><span class=\"p\">,<\/span> <span class=\"n\">loadContext<\/span><span class=\"p\">.<\/span><span class=\"n\">UserId<\/span><span class=\"p\">);<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">request<\/span><span class=\"p\">.<\/span><span class=\"n\">AddParameter<\/span><span class=\"p\">(<\/span><span class=\"s\">&#34;page&#34;<\/span><span class=\"p\">,<\/span> <span class=\"n\">loadContext<\/span><span class=\"p\">.<\/span><span class=\"n\">Page<\/span><span class=\"p\">.<\/span><span class=\"n\">ToString<\/span><span class=\"p\">());<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">return<\/span> <span class=\"n\">request<\/span><span class=\"p\">;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><p>Not only does it leverage existing code it follows the pattern most RestSharp\/Hammock users are used to, namely you create the request and then you add on parameters.<\/p>","category":[{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/categories\/windows-phone\/","term":"Windows Phone","label":"Windows Phone"}},{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/tags\/code\/","term":"Code","label":"Code"}},{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/tags\/csharp\/","term":"Csharp","label":"Csharp"}}]},{"title":"Selecting into an ObservableCollection in LINQ: a ToObservable() extension method for Enumerable","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/selecting-into-an-observablecollection-in-linq-a-toobservable-extension-method-for-enumerable\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/selecting-into-an-observablecollection-in-linq-a-toobservable-extension-method-for-enumerable\/","updated":"2026-10-18T02:41:51+00:00","published":"2012-02-09T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"I love me to some LINQ, especially some LINQ to XML (otherwise known as XLinq) for parsing meaty XML files into objects. Anywhere there is XML parsing going on in my app you&rsquo;ll see code similar to this:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 var list = (from review in reviews.","content":"<p>I love me to some LINQ, especially some LINQ to XML (otherwise known as XLinq) for parsing meaty XML files into objects. Anywhere there is XML parsing going on in my app you&rsquo;ll see code similar to this:<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\"> 1\n<\/span><span class=\"lnt\"> 2\n<\/span><span class=\"lnt\"> 3\n<\/span><span class=\"lnt\"> 4\n<\/span><span class=\"lnt\"> 5\n<\/span><span class=\"lnt\"> 6\n<\/span><span class=\"lnt\"> 7\n<\/span><span class=\"lnt\"> 8\n<\/span><span class=\"lnt\"> 9\n<\/span><span class=\"lnt\">10\n<\/span><span class=\"lnt\">11\n<\/span><span class=\"lnt\">12\n<\/span><span class=\"lnt\">13\n<\/span><span class=\"lnt\">14\n<\/span><span class=\"lnt\">15\n<\/span><span class=\"lnt\">16\n<\/span><span class=\"lnt\">17\n<\/span><span class=\"lnt\">18\n<\/span><span class=\"lnt\">19\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-csharp\" data-lang=\"csharp\"><span class=\"line\"><span class=\"cl\"><span class=\"kt\">var<\/span> <span class=\"n\">list<\/span> <span class=\"p\">=<\/span> <span class=\"p\">(<\/span><span class=\"k\">from<\/span> <span class=\"n\">review<\/span> <span class=\"k\">in<\/span> <span class=\"n\">reviews<\/span><span class=\"p\">.<\/span><span class=\"n\">Descendants<\/span><span class=\"p\">(<\/span><span class=\"s\">&#34;review&#34;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">select<\/span> <span class=\"k\">new<\/span> <span class=\"n\">BookReview<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">StartedAt<\/span> <span class=\"p\">=<\/span> <span class=\"p\">(<\/span><span class=\"kt\">string<\/span><span class=\"p\">)<\/span><span class=\"n\">review<\/span><span class=\"p\">.<\/span><span class=\"n\">Element<\/span><span class=\"p\">(<\/span><span class=\"s\">&#34;started_at&#34;<\/span><span class=\"p\">),<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">Book<\/span> <span class=\"p\">=<\/span> <span class=\"p\">(<\/span><span class=\"k\">from<\/span> <span class=\"n\">b<\/span> <span class=\"k\">in<\/span> <span class=\"n\">review<\/span><span class=\"p\">.<\/span><span class=\"n\">Elements<\/span><span class=\"p\">(<\/span><span class=\"s\">&#34;book&#34;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">select<\/span> <span class=\"k\">new<\/span> <span class=\"n\">Book<\/span><span class=\"p\">((<\/span><span class=\"kt\">string<\/span><span class=\"p\">)<\/span><span class=\"n\">b<\/span><span class=\"p\">.<\/span><span class=\"n\">Element<\/span><span class=\"p\">(<\/span><span class=\"s\">&#34;id&#34;<\/span><span class=\"p\">))<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">Title<\/span> <span class=\"p\">=<\/span> <span class=\"p\">(<\/span><span class=\"kt\">string<\/span><span class=\"p\">)<\/span><span class=\"n\">b<\/span><span class=\"p\">.<\/span><span class=\"n\">Element<\/span><span class=\"p\">(<\/span><span class=\"s\">&#34;title&#34;<\/span><span class=\"p\">),<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">CoverUrl<\/span> <span class=\"p\">=<\/span> <span class=\"k\">new<\/span> <span class=\"n\">Uri<\/span><span class=\"p\">((<\/span><span class=\"kt\">string<\/span><span class=\"p\">)<\/span><span class=\"n\">b<\/span><span class=\"p\">.<\/span><span class=\"n\">Element<\/span><span class=\"p\">(<\/span><span class=\"s\">&#34;image_url&#34;<\/span><span class=\"p\">)),<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">NumberOfPages<\/span> <span class=\"p\">=<\/span> <span class=\"p\">(<\/span><span class=\"kt\">string<\/span><span class=\"p\">)<\/span><span class=\"n\">b<\/span><span class=\"p\">.<\/span><span class=\"n\">Element<\/span><span class=\"p\">(<\/span><span class=\"s\">&#34;num_pages&#34;<\/span><span class=\"p\">),<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">AverageRating<\/span> <span class=\"p\">=<\/span> <span class=\"p\">(<\/span><span class=\"kt\">string<\/span><span class=\"p\">)<\/span><span class=\"n\">b<\/span><span class=\"p\">.<\/span><span class=\"n\">Element<\/span><span class=\"p\">(<\/span><span class=\"s\">&#34;average_rating&#34;<\/span><span class=\"p\">),<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">Description<\/span> <span class=\"p\">=<\/span> <span class=\"p\">(<\/span><span class=\"kt\">string<\/span><span class=\"p\">)<\/span><span class=\"n\">b<\/span><span class=\"p\">.<\/span><span class=\"n\">Element<\/span><span class=\"p\">(<\/span><span class=\"s\">&#34;description&#34;<\/span><span class=\"p\">).<\/span><span class=\"n\">Value<\/span><span class=\"p\">,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">Authors<\/span> <span class=\"p\">=<\/span> <span class=\"p\">(<\/span><span class=\"k\">from<\/span> <span class=\"n\">a<\/span> <span class=\"k\">in<\/span> <span class=\"n\">b<\/span><span class=\"p\">.<\/span><span class=\"n\">Descendants<\/span><span class=\"p\">(<\/span><span class=\"s\">&#34;author&#34;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">select<\/span> <span class=\"k\">new<\/span> <span class=\"n\">Author<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">Name<\/span> <span class=\"p\">=<\/span> <span class=\"p\">(<\/span><span class=\"kt\">string<\/span><span class=\"p\">)<\/span><span class=\"n\">a<\/span><span class=\"p\">.<\/span><span class=\"n\">Element<\/span><span class=\"p\">(<\/span><span class=\"s\">&#34;name&#34;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}).<\/span><span class=\"n\">ToObservable<\/span><span class=\"p\">&lt;<\/span><span class=\"n\">Author<\/span><span class=\"p\">&gt;()<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}).<\/span><span class=\"n\">SingleOrDefault<\/span><span class=\"p\">()<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}).<\/span><span class=\"n\">ToList<\/span><span class=\"p\">();<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><p>This is a medium complexity example, I&rsquo;m selecting a list of <code>BookReview<\/code> objects which contains a <code>Book<\/code> which in turn has a collection of <code>Author<\/code> objects.<\/p>\n<p>One thing to pay attention to is that the default return type for a collection of items returned via LINQ is a <code>Enumerable<\/code> and if you&rsquo;re using a different collection type you&rsquo;ll need to use one of the built-in extension methods to convert it to the appropriate collection type. You can see where I&rsquo;m doing this on the last line above with the call to <code>ToList()<\/code>.<\/p>\n<p>There are built-in extension methods to convert to List, Dictionary, Array and a bevy of others but not <code>ObservableCollection<\/code>, which you&rsquo;re probably using in some form if you&rsquo;re data binding your collection to your UI. You could select into an Enumerable and then manually add each item into your ObservableCollection but that&rsquo;s no fun and it&rsquo;s much simpler to just write your own Enumerable extension method to take care of it:<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><span class=\"lnt\">2\n<\/span><span class=\"lnt\">3\n<\/span><span class=\"lnt\">4\n<\/span><span class=\"lnt\">5\n<\/span><span class=\"lnt\">6\n<\/span><span class=\"lnt\">7\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-csharp\" data-lang=\"csharp\"><span class=\"line\"><span class=\"cl\"><span class=\"kd\">public<\/span> <span class=\"kd\">static<\/span> <span class=\"k\">class<\/span> <span class=\"nc\">Enumerable<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"kd\">public<\/span> <span class=\"kd\">static<\/span> <span class=\"n\">ObservableCollection<\/span><span class=\"p\">&lt;<\/span><span class=\"n\">TSource<\/span><span class=\"p\">&gt;<\/span> <span class=\"n\">ToObservable<\/span><span class=\"p\">&lt;<\/span><span class=\"n\">TSource<\/span><span class=\"p\">&gt;(<\/span><span class=\"k\">this<\/span> <span class=\"n\">IEnumerable<\/span><span class=\"p\">&lt;<\/span><span class=\"n\">TSource<\/span><span class=\"p\">&gt;<\/span> <span class=\"n\">source<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">return<\/span> <span class=\"k\">new<\/span> <span class=\"n\">ObservableCollection<\/span><span class=\"p\">&lt;<\/span><span class=\"n\">TSource<\/span><span class=\"p\">&gt;(<\/span><span class=\"n\">source<\/span><span class=\"p\">);<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><p>I&rsquo;m using it in the first sample to convert the Authors collection. Hope you find this useful, I know I use it all the time in my Windows Phone apps!<\/p>\n<p>By the way it&rsquo;s also a &ldquo;gist&rdquo;, a version controlled snippet, over on github.com: <a href=\"https:\/\/gist.github.com\/fcf07029eec152ec80f7\">LinqExtensions.cs<\/a>.<\/p>"},{"title":"Tips for Writing Windows Phone Applications End-to-End","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/tips-for-writing-windows-phone-applications-end-to-end\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/tips-for-writing-windows-phone-applications-end-to-end\/","updated":"2026-10-18T02:41:51+00:00","published":"2012-02-06T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"I&rsquo;m currently working on a GoodReads client for Windows Phone and while I&rsquo;ve written a ton of phone code for various demos, API smoke testing, targeted &ldquo;how do I&rdquo; questions, etc. it&rsquo;s an entirely different beast to write an application end-to-end. The technical questions are often the easiest and if you&rsquo;ve been coding for more than a few years (or months, you rockstar you) the problems and questions that keep you up at night shift from technical (&ldquo;how do I save an image to the phone?","content":"<p>I&rsquo;m currently working on a <a href=\"http:\/\/www.goodreads.com\/\">GoodReads<\/a> client for Windows Phone and while I&rsquo;ve written a ton of phone code for various demos, API smoke testing, targeted &ldquo;how do I&rdquo; questions, etc. it&rsquo;s an entirely different beast to write an application end-to-end. The technical questions are often the easiest and if you&rsquo;ve been coding for more than a few years (or months, you rockstar you) the problems and questions that keep you up at night shift from technical (&ldquo;how do I save an image to the phone?&rdquo;) to architectural (&ldquo;what&rsquo;s the best pattern for integrating a REST client into my caching framework?&rdquo;).<\/p>\n<p>As a knowledge and data capturing exercise I&rsquo;m collecting the various articles, resources and code snippets that I found extremely helpful as I fleshed out my application, grouped by the order I came across the issues and roughly the order I architected my application.<\/p>\n<p>This is a &ldquo;live&rdquo; document that will to continue to grow as I finish my application. Also if you&rsquo;ve found articles that made a key difference in your application development let me know so I can check them out!<\/p>\n<h2 id=\"user-experienceui-design\">User Experience\/UI Design<\/h2>\n<p><a href=\"https:\/\/whiskeyandcode.com\/images\/IMG_0117.jpg\"><img src=\"https:\/\/whiskeyandcode.com\/images\/IMG_0117_thumb.jpg\" alt=\"Kudu UI Sketch\" title=\"Kudu UI Sketch\"><\/a><\/p>\n<p>Close down Visual Studio, stop building up your class library and do something that you&rsquo;ve been told is anathema to good development. Start with your UI and build out from there. It is key you understand the layout of your application, roughly what each page will look, what functions it&rsquo;ll perform, what states it can be in. Seriously. I crafted this lovely rich client that modeled my entire backend in a clean, crisp way and then I threw it all away. Why? Because when I started mapping the client to my UI I was making 3 or 4 calls to the backend when if I&rsquo;d just understand HOW I&rsquo;d be displaying it I would have crafted my middle-layer differently. It&rsquo;s one of the dirty secrets of creating lean and mean apps, you do end up building you middle-tier to optimize for the end result, not as some model that has been delivered from high on top.<\/p>\n<ul>\n<li>\n<p>When you need a little more structure than just a piece of blank paper try the <a href=\"http:\/\/www.uistencils.com\/products\/windows-phone-sketch-pad\">Windows Phone Sketch Pad<\/a> from UI Stencils. I love this sketch pad and it helped me a ton in crafting my UI and work flow.<\/p>\n<\/li>\n<li>\n<p>Make sure you&rsquo;re familiar with the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/hh202915(v=vs.92).aspx\">User Experience Design Guidelines for Windows Phone<\/a> over on MSDN as you start thinking about your application.<\/p>\n<\/li>\n<li>\n<p>The <a href=\"http:\/\/windows.microsoft.com\/en-US\/windows7\/products\/features\/snipping-tool\">Windows 7 Snipping Tool<\/a>. It&rsquo;s already on your machine (you are running Win7 right?) and I use it about a dozen times a day to screen grab my current page and drop it into Paint.NET to take pixel measurements to make sure my UI is as close Metro design guidelines as possible.<\/p>\n<\/li>\n<\/ul>\n<h2 id=\"architecture\">Architecture<\/h2>\n<ul>\n<li>\n<p>You&rsquo;ll need to think about caching if you deal with any significant amount of data and on a mobile device that pretty much means any data at all. I&rsquo;m using Shawn Burke&rsquo;s excellent web request data caching framework <a href=\"http:\/\/agfx.codeplex.com\/\">AgFx<\/a>.<\/p>\n<\/li>\n<li>\n<p>I am using a form of MVVM but I haven&rsquo;t jumped on board with either Prism or MVVM Light, mostly because I&rsquo;m a nerd and I don&rsquo;t trust anyone else&rsquo;s code until I&rsquo;ve written my own framework, formed my own opinion of how things should be done and then adopt the one that I best align with.<\/p>\n<\/li>\n<\/ul>\n<h2 id=\"loginauthentication\">Login\/Authentication<\/h2>\n<p>A great number of applications are skins over some backend that requires a login and these days there is a good chance it&rsquo;s via OAuth. It&rsquo;s actually not that hard but it can be a huge in the arse to debug and get just right as each back-end does things just slightly differently. Here are the articles that helped me along:<\/p>\n<ul>\n<li>\n<p>From my colleague Sam Jarawan I cribbed a bunch of code from his article, &ldquo;<a href=\"http:\/\/samjarawan.blogspot.com\/2010\/09\/building-real-windows-phone-7-twitter_18.html\">Building a &lsquo;real&rsquo; Windows Phone 7 Twitter App Part 2 - oAuth<\/a>&rdquo;<\/p>\n<\/li>\n<li>\n<p>I used both excellent .NET REST helper libs <a href=\"https:\/\/github.com\/danielcrenna\/hammock\">Hammock<\/a> &amp; <a href=\"http:\/\/restsharp.org\/\">RestSharp<\/a>. I ran into some issues with params with square brackets using Hammock so had to switch to RestSharp but I honestly couldn&rsquo;t find any major different between the two to recommend one over the other. RestSharp seems to have a slightly more active community and docs.<\/p>\n<\/li>\n<li>\n<p>A lot of apps simply won&rsquo;t work if you don&rsquo;t log in so you want to conditionally show a login page based on some state. For that turn to Peter Torr&rsquo;s blog post, &ldquo;<a href=\"http:\/\/blogs.msdn.com\/b\/ptorr\/archive\/2010\/08\/28\/redirecting-an-initial-navigation.aspx\">Redirecting an initial navigation<\/a>&rdquo;.<\/p>\n<\/li>\n<\/ul>\n<h2 id=\"certification\">Certification<\/h2>\n<ul>\n<li>My app hasn&rsquo;t yet been submitted for certification but I&rsquo;ve already been using the <a href=\"http:\/\/www.silverlightshow.net\/items\/Windows-Phone-7-Application-Certification-Cheat-Sheet.aspx\">Windows Phone 7 Application Certification Cheat Sheet<\/a> to make sure my app will sail through without any issues.<\/li>\n<\/ul>\n<h2 id=\"tools\">Tools<\/h2>\n<p>My supporting cast of tools.<\/p>\n<ul>\n<li>\n<p><a href=\"http:\/\/code.google.com\/p\/msysgit\/\">Git<\/a> - Whether you&rsquo;re a lone wolf, a pack of one, coding the next great thing or a corporate developer you need to version control. If you&rsquo;re in a company you probably already have a solution but if you&rsquo;re a coffee shop coder you may not be using anything and that my friend is a mistake. You&rsquo;ll get on a caffeine buzz and decide to refactor your entire application only to get distracted and find your app in pieces wishing you could just get back to how everything was pre-latt\u00e9. There are a ton of great source control systems but lately I&rsquo;ve been using git like all the cool kids. To do local versioning is a snap, without the need for a server or service running. I also still love Subversion and the server I put in place at my last job is still rocking along being a source control hero.<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/www.dropbox.com\/\">Dropbox<\/a> - I code on three different machines and Dropbox makes it possible for me not to worry if I have the latest source for my project. Best of all it works well with my source control so I get portability as well as versioning.<\/p>\n<\/li>\n<\/ul>","category":{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/categories\/windows-phone\/","term":"Windows Phone","label":"Windows Phone"}}},{"title":"Recreating the Windows Phone 7 message bubble style in Silverlight","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/recreating-the-windows-phone-7-message-bubble-style-in-silverlight\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/recreating-the-windows-phone-7-message-bubble-style-in-silverlight\/","updated":"2026-10-18T02:41:51+00:00","published":"2011-07-22T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"In a little app I&rsquo;m working on to exercise some new Mango features I needed to create the message &ldquo;bubble&rdquo; and oddly enough didn&rsquo;t stumble across any samples I could easily use even though a large number of apps have recreated this style, most likely because it&rsquo;s so easy to do.","content":"<p>In a little app I&rsquo;m working on to exercise some new Mango features I needed to create the message &ldquo;bubble&rdquo; and oddly enough didn&rsquo;t stumble across any samples I could easily use even though a large number of apps have recreated this style, most likely because it&rsquo;s so easy to do.<\/p>\n<p><a href=\"https:\/\/whiskeyandcode.com\/images\/image_5.png\"><img src=\"https:\/\/whiskeyandcode.com\/images\/image_thumb_5.png\" alt=\"image\" title=\"image\"><\/a><\/p>\n<p>Here was my first take and it&rsquo;s very hard-coded to the above look but it should be trivial to change it around. Also there are dozen ways you could make this more reusable, either as a template for a <code>ContentControl<\/code> or as a new control. If anyone has any suggestions for improvements or a better resource I&rsquo;d love to see it!<\/p>\n<h2 id=\"xaml\">XAML<\/h2>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\"> 1\n<\/span><span class=\"lnt\"> 2\n<\/span><span class=\"lnt\"> 3\n<\/span><span class=\"lnt\"> 4\n<\/span><span class=\"lnt\"> 5\n<\/span><span class=\"lnt\"> 6\n<\/span><span class=\"lnt\"> 7\n<\/span><span class=\"lnt\"> 8\n<\/span><span class=\"lnt\"> 9\n<\/span><span class=\"lnt\">10\n<\/span><span class=\"lnt\">11\n<\/span><span class=\"lnt\">12\n<\/span><span class=\"lnt\">13\n<\/span><span class=\"lnt\">14\n<\/span><span class=\"lnt\">15\n<\/span><span class=\"lnt\">16\n<\/span><span class=\"lnt\">17\n<\/span><span class=\"lnt\">18\n<\/span><span class=\"lnt\">19\n<\/span><span class=\"lnt\">20\n<\/span><span class=\"lnt\">21\n<\/span><span class=\"lnt\">22\n<\/span><span class=\"lnt\">23\n<\/span><span class=\"lnt\">24\n<\/span><span class=\"lnt\">25\n<\/span><span class=\"lnt\">26\n<\/span><span class=\"lnt\">27\n<\/span><span class=\"lnt\">28\n<\/span><span class=\"lnt\">29\n<\/span><span class=\"lnt\">30\n<\/span><span class=\"lnt\">31\n<\/span><span class=\"lnt\">32\n<\/span><span class=\"lnt\">33\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-xml\" data-lang=\"xml\"><span class=\"line\"><span class=\"cl\"><span class=\"c\">&lt;!-- bubble --&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nt\">&lt;Grid<\/span> <span class=\"na\">Grid.Column=<\/span><span class=\"s\">&#34;1&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">Margin=<\/span><span class=\"s\">&#34;12,6,12,0&#34;<\/span><span class=\"nt\">&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;Grid.RowDefinitions&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;RowDefinition<\/span> <span class=\"na\">Height=<\/span><span class=\"s\">&#34;Auto&#34;<\/span> <span class=\"nt\">\/&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;RowDefinition<\/span> <span class=\"na\">Height=<\/span><span class=\"s\">&#34;Auto&#34;<\/span> <span class=\"nt\">\/&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;\/Grid.RowDefinitions&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;Path<\/span> <span class=\"na\">Data=<\/span><span class=\"s\">&#34;M 16,12 16,0 0,12&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">Fill=<\/span><span class=\"s\">&#34;{StaticResource PhoneAccentBrush}&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">HorizontalAlignment=<\/span><span class=\"s\">&#34;Right&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">Margin=<\/span><span class=\"s\">&#34;0,0,12,0&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">UseLayoutRounding=<\/span><span class=\"s\">&#34;False&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">VerticalAlignment=<\/span><span class=\"s\">&#34;Top&#34;<\/span> <span class=\"nt\">\/&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"c\">&lt;!-- Your actual content here --&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;StackPanel<\/span> <span class=\"na\">Grid.Row=<\/span><span class=\"s\">&#34;1&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">Background=<\/span><span class=\"s\">&#34;{StaticResource PhoneAccentBrush}&#34;<\/span><span class=\"nt\">&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;TextBlock<\/span> <span class=\"na\">Text=<\/span><span class=\"s\">&#34;{Binding Mood}&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">Style=<\/span><span class=\"s\">&#34;{StaticResource PhoneTextNormalStyle}&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">FontWeight=<\/span><span class=\"s\">&#34;Bold&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">TextWrapping=<\/span><span class=\"s\">&#34;Wrap&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">Margin=<\/span><span class=\"s\">&#34;6,12,6,6&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">HorizontalAlignment=<\/span><span class=\"s\">&#34;Left&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">VerticalAlignment=<\/span><span class=\"s\">&#34;Top&#34;<\/span> <span class=\"nt\">\/&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;TextBlock<\/span> <span class=\"na\">Text=<\/span><span class=\"s\">&#34;{Binding LastUpdated, StringFormat=&#39;g&#39;}&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">HorizontalAlignment=<\/span><span class=\"s\">&#34;Right&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">VerticalAlignment=<\/span><span class=\"s\">&#34;Top&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">Margin=<\/span><span class=\"s\">&#34;6,0,6,6&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">Style=<\/span><span class=\"s\">&#34;{StaticResource PhoneTextSubtleStyle}&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">FontFamily=<\/span><span class=\"s\">&#34;Segoe WP SemiLight&#34;<\/span> <span class=\"nt\">\/&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;\/StackPanel&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nt\">&lt;\/Grid&gt;<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><p>Note for the sharp-eyed I&rsquo;m using a feature that is new for Mango that exists in Silverlight 4 which is default string formatting in bindings.<\/p>","category":{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/categories\/windows-phone\/","term":"Windows Phone","label":"Windows Phone"}}},{"title":"Extension method to get a page\u2019s ProgressIndicator","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/extension-method-to-get-a-pages-progressindicator\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/extension-method-to-get-a-pages-progressindicator\/","updated":"2026-10-18T02:41:51+00:00","published":"2011-07-20T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"In Mango we added the ability to interact with the shell&rsquo;s native progress indicator along the top of the page. This is a great way to maintain UI consistency with the phone as well as get a smooth progress animation because the system is handling the animation vs.","content":"<p>In Mango we added the ability to interact with the shell&rsquo;s native progress indicator along the top of the page. This is a great way to maintain UI consistency with the phone as well as get a smooth progress animation because the system is handling the animation vs. the Silverlight runtime. Here I&rsquo;m recreating the &lsquo;save to phone&rsquo; menu item you can see in the pictures hub by adding a &ldquo;Saving picture&hellip;&rdquo; progress indicator:<\/p>\n<p><a href=\"https:\/\/whiskeyandcode.com\/images\/image_4.png\"><img src=\"https:\/\/whiskeyandcode.com\/images\/image_thumb_4.png\" alt=\"image\" title=\"image\"><\/a><\/p>\n<p>There are some great articles on using the new ProgressIndicator out there and I won&rsquo;t do yet another intro blog post but I did want to share a little extension method I wrote to grab it from the page and avoid some of the annoying initialization code that you end up writing over and over again.<\/p>\n<p>Some of my favorite ProgressIndicator articles so far for those looking to explore this in more depth are:<\/p>\n<ul>\n<li><a href=\"http:\/\/www.jeff.wilcox.name\/2011\/07\/creating-a-global-progressindicator-experience-using-the-windows-phone-7-1-sdk-beta-2\/\">Creating a global ProgressIndicator experience using the Windows Phone 7.1 SDK Beta 2<\/a><\/li>\n<li><a href=\"http:\/\/danielvaughan.org\/post\/Binding-the-WP7-ProgressIndicator-in-XAML.aspx\">Binding the WP7 ProgressIndicator in XAML<\/a><\/li>\n<\/ul>\n<p>And here is my little extension method I&rsquo;ve found useful on a few pages:<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\"> 1\n<\/span><span class=\"lnt\"> 2\n<\/span><span class=\"lnt\"> 3\n<\/span><span class=\"lnt\"> 4\n<\/span><span class=\"lnt\"> 5\n<\/span><span class=\"lnt\"> 6\n<\/span><span class=\"lnt\"> 7\n<\/span><span class=\"lnt\"> 8\n<\/span><span class=\"lnt\"> 9\n<\/span><span class=\"lnt\">10\n<\/span><span class=\"lnt\">11\n<\/span><span class=\"lnt\">12\n<\/span><span class=\"lnt\">13\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-csharp\" data-lang=\"csharp\"><span class=\"line\"><span class=\"cl\"><span class=\"kd\">public<\/span> <span class=\"kd\">static<\/span> <span class=\"k\">class<\/span> <span class=\"nc\">Extensions<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"kd\">public<\/span> <span class=\"kd\">static<\/span> <span class=\"n\">ProgressIndicator<\/span> <span class=\"n\">GetProgressIndicator<\/span><span class=\"p\">(<\/span><span class=\"k\">this<\/span> <span class=\"n\">PhoneApplicationPage<\/span> <span class=\"n\">page<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"kt\">var<\/span> <span class=\"n\">progressIndicator<\/span> <span class=\"p\">=<\/span> <span class=\"n\">SystemTray<\/span><span class=\"p\">.<\/span><span class=\"n\">ProgressIndicator<\/span><span class=\"p\">;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">progressIndicator<\/span> <span class=\"p\">==<\/span> <span class=\"kc\">null<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">progressIndicator<\/span> <span class=\"p\">=<\/span> <span class=\"k\">new<\/span> <span class=\"n\">ProgressIndicator<\/span><span class=\"p\">();<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">SystemTray<\/span><span class=\"p\">.<\/span><span class=\"n\">SetProgressIndicator<\/span><span class=\"p\">(<\/span><span class=\"n\">page<\/span><span class=\"p\">,<\/span> <span class=\"n\">progressIndicator<\/span><span class=\"p\">);<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">return<\/span> <span class=\"n\">progressIndicator<\/span><span class=\"p\">;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><p>I&rsquo;m playing with using some of the various code snippet websites out there and this is embedded from <a href=\"http:\/\/www.smipple.net\/snippet\/Shawn%20Oster\/GetProgressIndicator%20extension%20method\">Smipple<\/a>. I&rsquo;d love to see more Windows Phone snippets pop up on these sites.<\/p>\n<p><strong>UPDATE:<\/strong> Scratch the idea of embedding Smipple snippets via embed code, it looks awesome but seems to tweak my formatting, going back to good old syntax highlighted.<\/p>","category":{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/categories\/windows-phone\/","term":"Windows Phone","label":"Windows Phone"}}},{"title":"What\u2019s New for Windows Phone Development with Silverlight (in Mango) - MIX11 Session Online","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/whats-new-for-windows-phone-development-with-silverlight-in-mango-mix11-session-online\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/whats-new-for-windows-phone-development-with-silverlight-in-mango-mix11-session-online\/","updated":"2026-10-18T02:41:51+00:00","published":"2011-04-20T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"My talk from MIX11 has made its way online and for those that couldn&rsquo;t attend (or those that were still recovering from the great attendee party and discovered that 9am is way too early to attempt to move) a video of my session is online over only channel9 available for streaming or downloading.","content":"<p>My talk from MIX11 has made its way online and for those that couldn&rsquo;t attend (or those that were still recovering from the great attendee party and discovered that 9am is way too early to attempt to move) a video of my session is online over only channel9 available for streaming or downloading.<\/p>\n<p>Channel9: <a href=\"http:\/\/channel9.msdn.com\/events\/mix\/mix11\/DVC15\">What&rsquo;s New for Windows Phone Development with Silverlight?<\/a><\/p>\n<p>Also for your direct viewing pleasure here it is embedded.<\/p>\n<iframe style=\"width: 512px; height: 288px\" src=\"http:\/\/channel9.msdn.com\/events\/mix\/mix11\/DVC15\/player?w=512&h=288\" frameborder=\"0\" scrolling=\"no\"><\/iframe>\n<p>For anyone that watches it and has questions, or people in the audience that didn&rsquo;t get a chance to ask one feel free to drop me a line in the comments and I&rsquo;ll do the best I can to find you the answers.<\/p>\n<p>Also because not everyone had time to fill out their speaker evals if there is a type of content or way you&rsquo;d like to see this content delivered in the future I&rsquo;d love to hear your feedback in general. More or less code? More technical details, would you prefer to see flashy demos that rock but require a lot of code or more simple demos that clearly show the feature?<\/p>\n<p>MIX is for <strong>you<\/strong> so anything we can do to help improve content is greatly appreciated.<\/p>","category":{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/categories\/windows-phone\/","term":"Windows Phone","label":"Windows Phone"}}},{"title":"Crazy Coincidental Coding, Batman!","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/crazy-coincidental-coding-batman\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/crazy-coincidental-coding-batman\/","updated":"2026-10-18T02:41:51+00:00","published":"2010-08-18T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"My Windows Phone cohort and all-round good guy Peter Torr posted on exactly the same topic that I did at almost exactly the same time&hellip; and we didn&rsquo;t co-ordinate it at all!\nVirtualizing Data in Windows Phone 7 Silverlight Applications\nCreepy, huh?","content":"<p>My Windows Phone cohort and all-round good guy <a href=\"http:\/\/blogs.msdn.com\/b\/ptorr\/\">Peter Torr<\/a> posted on <em>exactly<\/em> the same topic that I did at almost exactly the same time&hellip; and we didn&rsquo;t co-ordinate it at all!<\/p>\n<p><a href=\"http:\/\/blogs.msdn.com\/b\/ptorr\/archive\/2010\/08\/16\/virtualizing-data-in-windows-phone-7-silverlight-applications.aspx\">Virtualizing Data in Windows Phone 7 Silverlight Applications<\/a><\/p>\n<p>Creepy, huh?<\/p>\n<p>Peter has a great overview of virtualization and shows a different sample and given how tricky virtualization can be I highly recommend you also read his article.<\/p>","category":{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/categories\/windows-phone\/","term":"Windows Phone","label":"Windows Phone"}}},{"title":"Improving ListBox Performance in Silverlight for Windows Phone 7 Data Virtualization","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/improving-listbox-performance-in-silverlight-for-windows-phone-7-data-virtualization\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/improving-listbox-performance-in-silverlight-for-windows-phone-7-data-virtualization\/","updated":"2026-10-18T02:41:51+00:00","published":"2010-08-17T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"There is a lot of data out there; on the internet, tucked away in databases, sitting patiently on the other side of a REST web service just waiting to pounce on your unsuspecting Windows Phone application that just wants to display a little slice of it all so people can read it, touch it and generally make sense of it.","content":"<p>There is a lot of data out there; on the internet, tucked away in databases, sitting patiently on the other side of a REST web service just waiting to pounce on your unsuspecting Windows Phone application that just wants to display a little slice of it all so people can read it, touch it and generally make sense of it. The problem is there is a lot of it, so what is a poor unsuspecting application to do, especially when it&rsquo;s been crammed into a form factor that doesn&rsquo;t allow ever expanding memory upgrades?<\/p>\n<p>In this post and a few to come I&rsquo;m going to explore the various ways you can work with the ListBox (the go-to control for displaying lists of data) in your application to keep it speedy and responsive. Today we&rsquo;re going to start with a feature added in Silverlight for Windows Phone: Data Virtualization.<\/p>\n<h2 id=\"data-virtualization\">Data Virtualization<\/h2>\n<p>Data virtualization is the concept of only loading &ldquo;just enough&rdquo; data to fill out your UI and be useful to interact with. This is particularly useful if your data set is large and can&rsquo;t all fit into memory at the same time. Good examples are the 3,000 images you took of various pancakes shaped like childhood cartoon characters or all 23,083 remixes of The Postal Services &ldquo;[The District Sleeps Alone Tonight][1] you have loaded up on your phone.<\/p>\n<p>Data virtualization in Silverlight is accomplished when you bind a custom IList implementation to a ListBox with a data template. Let&rsquo;s break that statement down by creating a very na\u00efve virtualized list that simulates a list of 10,000 song objects.<\/p>\n<p>[1]: <a href=\"http:\/\/social.zune.net\/album\/The-Postal-Service\/The-District-Sleeps-Alone-Tonight-(Maxi-Single)\/b1535600-0100-11db-89ca-0019b92a3933\/details\">http:\/\/social.zune.net\/album\/The-Postal-Service\/The-District-Sleeps-Alone-Tonight-(Maxi-Single)\/b1535600-0100-11db-89ca-0019b92a3933\/details<\/a>)<\/p>\n<h3 id=\"implement-ilist\">Implement IList<\/h3>\n<p>This isn&rsquo;t as daunting as it might seem, there are really only two methods you need to implement: Count and the indexer property. Everything else can throw <code>NotImplemented<\/code>. Count returns, well, the count of items while the indexer returns the actual item being requested by index.<\/p>\n<p>Most of the magic happens in the indexer. When an item is requested you now have a chance to go off and grab your data, fabricate it (such as using a <code>WriteableBitmap<\/code>), load it from <code>IsolatedStorage<\/code>, compute it based on index or generally return whatever makes sense.<\/p>\n<p>Here I&rsquo;m just creating a new Song class and setting its Title to a string that matches the requested index but in reality you&rsquo;d be doing some parsing\/loading\/fetching here.<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\"> 1\n<\/span><span class=\"lnt\"> 2\n<\/span><span class=\"lnt\"> 3\n<\/span><span class=\"lnt\"> 4\n<\/span><span class=\"lnt\"> 5\n<\/span><span class=\"lnt\"> 6\n<\/span><span class=\"lnt\"> 7\n<\/span><span class=\"lnt\"> 8\n<\/span><span class=\"lnt\"> 9\n<\/span><span class=\"lnt\">10\n<\/span><span class=\"lnt\">11\n<\/span><span class=\"lnt\">12\n<\/span><span class=\"lnt\">13\n<\/span><span class=\"lnt\">14\n<\/span><span class=\"lnt\">15\n<\/span><span class=\"lnt\">16\n<\/span><span class=\"lnt\">17\n<\/span><span class=\"lnt\">18\n<\/span><span class=\"lnt\">19\n<\/span><span class=\"lnt\">20\n<\/span><span class=\"lnt\">21\n<\/span><span class=\"lnt\">22\n<\/span><span class=\"lnt\">23\n<\/span><span class=\"lnt\">24\n<\/span><span class=\"lnt\">25\n<\/span><span class=\"lnt\">26\n<\/span><span class=\"lnt\">27\n<\/span><span class=\"lnt\">28\n<\/span><span class=\"lnt\">29\n<\/span><span class=\"lnt\">30\n<\/span><span class=\"lnt\">31\n<\/span><span class=\"lnt\">32\n<\/span><span class=\"lnt\">33\n<\/span><span class=\"lnt\">34\n<\/span><span class=\"lnt\">35\n<\/span><span class=\"lnt\">36\n<\/span><span class=\"lnt\">37\n<\/span><span class=\"lnt\">38\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-csharp\" data-lang=\"csharp\"><span class=\"line\"><span class=\"cl\"><span class=\"kd\">public<\/span> <span class=\"k\">class<\/span> <span class=\"nc\">Song<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"kd\">public<\/span> <span class=\"kt\">string<\/span> <span class=\"n\">Title<\/span> <span class=\"p\">{<\/span> <span class=\"k\">get<\/span><span class=\"p\">;<\/span> <span class=\"k\">set<\/span><span class=\"p\">;<\/span> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"kd\">public<\/span> <span class=\"kt\">string<\/span> <span class=\"n\">Length<\/span> <span class=\"p\">{<\/span> <span class=\"k\">get<\/span><span class=\"p\">;<\/span> <span class=\"k\">set<\/span><span class=\"p\">;<\/span> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"kd\">public<\/span> <span class=\"k\">class<\/span> <span class=\"nc\">VirtualSongList<\/span> <span class=\"p\">:<\/span> <span class=\"n\">IList<\/span><span class=\"p\">&lt;<\/span><span class=\"kt\">string<\/span><span class=\"p\">&gt;,<\/span> <span class=\"n\">IList<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"cs\">\/\/\/ &lt;summary&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"cs\">\/\/\/ Return the total number of items in your list.<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"cs\">\/\/\/ &lt;\/summary&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"kd\">public<\/span> <span class=\"kt\">int<\/span> <span class=\"n\">Count<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">get<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">return<\/span> <span class=\"m\">10000<\/span><span class=\"p\">;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"kt\">object<\/span> <span class=\"n\">IList<\/span><span class=\"p\">.<\/span><span class=\"k\">this<\/span><span class=\"p\">[<\/span><span class=\"kt\">int<\/span> <span class=\"n\">index<\/span><span class=\"p\">]<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">get<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"c1\">\/\/ here is where the magic happens, create\/load your data on the fly.<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">Debug<\/span><span class=\"p\">.<\/span><span class=\"n\">WriteLine<\/span><span class=\"p\">(<\/span><span class=\"s\">&#34;Requsted item &#34;<\/span> <span class=\"p\">+<\/span> <span class=\"n\">index<\/span><span class=\"p\">.<\/span><span class=\"n\">ToString<\/span><span class=\"p\">());<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">return<\/span> <span class=\"k\">new<\/span> <span class=\"n\">Song<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span> <span class=\"n\">title<\/span><span class=\"p\">:<\/span> <span class=\"n\">Song<\/span> <span class=\"s\">&#34; + index.ToString() };\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"s\"><\/span> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">set<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">throw<\/span> <span class=\"k\">new<\/span> <span class=\"n\">NotImplementedException<\/span><span class=\"p\">();<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"c1\">\/\/ everything else throws NotImplemented Exception.<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"c1\">\/\/ .<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"c1\">\/\/ .<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"c1\">\/\/ .<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><p>NOTE: While the code is rather easy to implement it&rsquo;s boring, mind numbingly boring so I&rsquo;ve made the above <a href=\"https:\/\/whiskeyandcode.com\/downloads\/VirtualSongList.cs\">implementation available for your source downloading<\/a> pleasure.<\/p>\n<h3 id=\"bind-to-listbox\">Bind to ListBox<\/h3>\n<p>This is pretty straight-forward stuff, you&rsquo;ll need to bind your new fancy list to the ListBox in question.<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><span class=\"lnt\">2\n<\/span><span class=\"lnt\">3\n<\/span><span class=\"lnt\">4\n<\/span><span class=\"lnt\">5\n<\/span><span class=\"lnt\">6\n<\/span><span class=\"lnt\">7\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-csharp\" data-lang=\"csharp\"><span class=\"line\"><span class=\"cl\"><span class=\"c1\">\/\/ Constructor<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"kd\">public<\/span> <span class=\"n\">MainPage<\/span><span class=\"p\">()<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">InitializeComponent<\/span><span class=\"p\">();<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">ItemList<\/span><span class=\"p\">.<\/span><span class=\"n\">ItemsSource<\/span> <span class=\"p\">=<\/span> <span class=\"k\">new<\/span> <span class=\"n\">VirtualSongList<\/span><span class=\"p\">();<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><h3 id=\"datatemplate\">DataTemplate<\/h3>\n<p>One caveat is your <code>ListBox<\/code> needs to use a <code>DataTemplate<\/code> otherwise virtualization doesn&rsquo;t kick in. The virtualization code-path needs to make a few assumptions about your data and having a <code>DataTemplate<\/code> helps it down that path. Without it all your hard work will go down the drain as the first time you bind your list every single item will be requested.<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><span class=\"lnt\">2\n<\/span><span class=\"lnt\">3\n<\/span><span class=\"lnt\">4\n<\/span><span class=\"lnt\">5\n<\/span><span class=\"lnt\">6\n<\/span><span class=\"lnt\">7\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-xml\" data-lang=\"xml\"><span class=\"line\"><span class=\"cl\"><span class=\"nt\">&lt;ListBox<\/span> <span class=\"na\">x:Name=<\/span><span class=\"s\">&#34;ItemList&#34;<\/span><span class=\"nt\">&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;ListBox.ItemTemplate&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;DataTemplate&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;TextBlock<\/span> <span class=\"na\">Text=<\/span><span class=\"s\">&#34;{Binding Title}&#34;<\/span> <span class=\"na\">FontSize=<\/span><span class=\"s\">&#34;32&#34;<\/span> <span class=\"nt\">\/&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;\/DataTemplate&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;\/ListBox.ItemTemplate&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nt\">&lt;\/ListBox&gt;<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><h3 id=\"in-action\">In Action<\/h3>\n<p>Let&rsquo;s take this code for a spin. An F5 and emulator launch later and we&rsquo;re looking at this pretty screen:<\/p>\n<p><a href=\"https:\/\/whiskeyandcode.com\/images\/image_1.png\"><img src=\"https:\/\/whiskeyandcode.com\/images\/image_thumb_1.png\" alt=\"image\" title=\"image\"><\/a><\/p>\n<p>As you can see we&rsquo;re using the Song created during the indexer call. To prove it&rsquo;s actually virtualized I added a Debug.WriteLine to output every time an item was requested:<\/p>\n<p><a href=\"https:\/\/whiskeyandcode.com\/images\/image_2.png\"><img src=\"https:\/\/whiskeyandcode.com\/images\/image_thumb_2.png\" alt=\"image\" title=\"image\"><\/a><\/p>\n<p>As you can see only 52 items were requested instead of the full 10,000. Why 52 instead of just 13? You always want a few items as buffer to give your virtualizing code a chance to actually do the work while items are being scrolled into view. For this reason we request about three page worth of data so your UI is always responsive.<\/p>\n<h3 id=\"extending-and-testing\">Extending And Testing<\/h3>\n<p>A virtualized list that only returns 10,000 items is a bit limited. A better, more testable pattern would be to create a separate repository or &ldquo;creator&rdquo; class that actually creates, counts and manages the objects. Your list should be nothing but that, a list.<\/p>\n<h3 id=\"caching\">Caching<\/h3>\n<p>Another thing to be aware of, and this is important to pay attention to, virtualization doesn&rsquo;t do any caching for you. This means if you scroll down and then back up your virtualized list will ask for index 0 again and if you have a na\u00efve implementation you will recreate item 0 over and over again. Depending on what you&rsquo;re returning you may want your repository to have some kind of object cache based on either time or current index.<\/p>\n<h3 id=\"when-to-virtualize\">When To Virtualize<\/h3>\n<p>If you attempt to do a lot in your indexer&rsquo;s get, where you actually make the &ldquo;virtual&rdquo; data real, you&rsquo;ll soon discover that your UI is now <em>worse<\/em> than it was before. That&rsquo;s because as you&rsquo;re scrolling it&rsquo;s getting hit over and over again so if you have an expensive creation you&rsquo;ll block your UI thread and everything will come to a screaming to a halt (some people say screeching halt but if I can&rsquo;t interact with my UI you will hear screaming).<\/p>\n<p>The general rule of thumb on when to use data virtualization is for large lists or medium lists whose items are heavy weight, such as images and expensive XAML objects. The bottom line is you just can&rsquo;t have all 3,000 images loaded up at once so you need some way to give the user a feeling of a nice, continuous smooth scroll.<\/p>\n<p>So how do you minimize the delay from heavy weight objects? Stay tuned for my next blog post when I talk about using proxy (some people like to say broker) objects to push as much of the real work into the background thread.<\/p>","category":{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/categories\/windows-phone\/","term":"Windows Phone","label":"Windows Phone"}}},{"title":"Getting Blur And DropShadow to work in the Windows Phone Emulator","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/getting-blur-and-dropshadow-to-work-in-the-windows-phone-emulator\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/getting-blur-and-dropshadow-to-work-in-the-windows-phone-emulator\/","updated":"2026-10-18T02:41:51+00:00","published":"2010-03-30T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"I&rsquo;ve noticed a few questions in the forums around why the Blur and DropShadow effects aren&rsquo;t showing up in the Windows Phone 7 Series emulator and the simple answer is you have to set CacheMode to BitmapCache.\n1 2 3 4 5 6 7 8 9 10 11 &lt;TextBlock Text=&#34;DropShadow&#34; Foreground=&#34;Black&#34; FontSize=&#34;48&#34; CacheMode=&#34;BitmapCache&#34;&gt; &lt;TextBlock.","content":"<p>I&rsquo;ve noticed a few questions in the forums around why the Blur and DropShadow effects aren&rsquo;t showing up in the Windows Phone 7 Series emulator and the simple answer is you have to set CacheMode to BitmapCache.<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\"> 1\n<\/span><span class=\"lnt\"> 2\n<\/span><span class=\"lnt\"> 3\n<\/span><span class=\"lnt\"> 4\n<\/span><span class=\"lnt\"> 5\n<\/span><span class=\"lnt\"> 6\n<\/span><span class=\"lnt\"> 7\n<\/span><span class=\"lnt\"> 8\n<\/span><span class=\"lnt\"> 9\n<\/span><span class=\"lnt\">10\n<\/span><span class=\"lnt\">11\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-xml\" data-lang=\"xml\"><span class=\"line\"><span class=\"cl\"><span class=\"nt\">&lt;TextBlock<\/span> <span class=\"na\">Text=<\/span><span class=\"s\">&#34;DropShadow&#34;<\/span> <span class=\"na\">Foreground=<\/span><span class=\"s\">&#34;Black&#34;<\/span> <span class=\"na\">FontSize=<\/span><span class=\"s\">&#34;48&#34;<\/span> <span class=\"na\">CacheMode=<\/span><span class=\"s\">&#34;BitmapCache&#34;<\/span><span class=\"nt\">&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;TextBlock.Effect&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;DropShadowEffect\/&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;\/TextBlock.Effect&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nt\">&lt;\/TextBlock&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nt\">&lt;TextBlock<\/span> <span class=\"na\">Text=<\/span><span class=\"s\">&#34;Blur&#34;<\/span> <span class=\"na\">Foreground=<\/span><span class=\"s\">&#34;Black&#34;<\/span> <span class=\"na\">FontSize=<\/span><span class=\"s\">&#34;48&#34;<\/span> <span class=\"na\">CacheMode=<\/span><span class=\"s\">&#34;BitmapCache&#34;<\/span><span class=\"nt\">&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;TextBlock.Effect&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;BlurEffect\/&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;\/TextBlock.Effect&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nt\">&lt;\/TextBlock&gt;<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><p>We are working on setting this automatically so you don&rsquo;t have to scratch your head each time you apply an effect and wonder why it looks fine on the design surface yet doesn&rsquo;t show up in the emulator.<\/p>\n<p><strong>UPDATE [7\/20\/2011]<\/strong> - I was looking through my blog and realized this needs to be updated. For anyone still looking for this information all the effects such as Blur &amp; DropShadow were intentionally disabled from the product for both 7.0 and the upcoming Mango. The performance hit that applications took from using these effects put too much of a strain on the system and it was decided that if we couldn&rsquo;t deliver a perfomant feature we would disable until such a time as we could.<\/p>","category":{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/categories\/windows-phone\/","term":"Windows Phone","label":"Windows Phone"}}},{"title":"Changing the Onscreen Keyboard (SIP) in Silverlight for Windows Phone 7 (WP7) using InputScope","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/changing-the-onscreen-keyboard-sip-in-silverlight-for-windows-phone-7-wp7-using-inputscope\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/changing-the-onscreen-keyboard-sip-in-silverlight-for-windows-phone-7-wp7-using-inputscope\/","updated":"2026-10-18T02:41:51+00:00","published":"2010-03-27T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"Given that the main way users enter text in your Windows Phone 7 Series application is via a tiny onscreen keyboard (a \u201cSoftware Input Panel\u201d or SIP) it&rsquo;s in everyone&rsquo;s best interest to make sure the right keys are available to the user when they need them.","content":"<p>Given that the main way users enter text in your Windows Phone 7 Series application is via a tiny onscreen keyboard (a \u201cSoftware Input Panel\u201d or SIP) it&rsquo;s in everyone&rsquo;s best interest to make sure the right keys are available to the user when they need them.<\/p>\n<p>A good example is when you go to enter a PIN number you really only want to see number-related keys, when composing a SMS you&rsquo;d like a quick way to insert an emoticon and if writing something longer you probably want auto-correction and replacement suggestions. The good news for Windows Phone developers is you can control which SIP layout is used and which auto-correct settings are enabled by setting the InputScope property of your TextBox.<\/p>\n<p>The concept of InputScope isn&rsquo;t new to XAML by the way, this concept already exists in WPF and was a nice fit with the native SIP behavior so if you&rsquo;ve used InputScope before you should be right at home.<\/p>\n<h2 id=\"setting-inputscope\">Setting InputScope<\/h2>\n<p>There are really three ways to set InputScope, two of which are cumbersome yet provide Intellisense and a third that is easy but requires you to know exactly which InputScope you&rsquo;re after.<\/p>\n<h3 id=\"via-xaml\">Via XAML<\/h3>\n<p>Doing it this way you&rsquo;ll get full Intellisense yet it&rsquo;s a lot of work to set a simple property:<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><span class=\"lnt\">2\n<\/span><span class=\"lnt\">3\n<\/span><span class=\"lnt\">4\n<\/span><span class=\"lnt\">5\n<\/span><span class=\"lnt\">6\n<\/span><span class=\"lnt\">7\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-xml\" data-lang=\"xml\"><span class=\"line\"><span class=\"cl\"><span class=\"nt\">&lt;TextBox&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;TextBox.InputScope&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;InputScope&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;InputScopeName<\/span> <span class=\"na\">NameValue=<\/span><span class=\"s\">&#34;Text&#34;<\/span> <span class=\"nt\">\/&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;\/InputScope&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;\/TextBox.InputScope&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nt\">&lt;\/TextBox&gt;<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><h3 id=\"via-code\">Via Code<\/h3>\n<p>If you&rsquo;re more the code-behind sort here it is in C#:<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><span class=\"lnt\">2\n<\/span><span class=\"lnt\">3\n<\/span><span class=\"lnt\">4\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-csharp\" data-lang=\"csharp\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">textBox1<\/span><span class=\"p\">.<\/span><span class=\"n\">InputScope<\/span> <span class=\"p\">=<\/span> <span class=\"k\">new<\/span> <span class=\"n\">InputScope<\/span><span class=\"p\">()<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">Names<\/span> <span class=\"p\">=<\/span> <span class=\"p\">{<\/span> <span class=\"k\">new<\/span> <span class=\"n\">InputScopeName<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span> <span class=\"n\">NameValue<\/span> <span class=\"p\">=<\/span> <span class=\"n\">InputScopeNameValue<\/span><span class=\"p\">.<\/span><span class=\"n\">Text<\/span> <span class=\"p\">}<\/span> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">};<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><h3 id=\"via-xaml-with-a-typeconvertor\">Via XAML with a TypeConvertor<\/h3>\n<p>Remember how in high school they&rsquo;d always teach you the hard way before showing you the easy version? Guilty as charged. If you already know the exact InputScopeNameValue you want to use, for example &lsquo;Text&rsquo;, then you can take advantage of the built-in TypeConvertor that is already wired up to the property and write this much easier XAML:<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-xml\" data-lang=\"xml\"><span class=\"line\"><span class=\"cl\"><span class=\"nt\">&lt;TextBox<\/span> <span class=\"na\">InputScope=<\/span><span class=\"s\">&#34;Text&#34;<\/span> <span class=\"nt\">\/&gt;<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><h2 id=\"inputscope-example-application\">InputScope Example Application<\/h2>\n<p>When we were bringing InputScopes from WPF to Silverlight for Windows Phone I wrote a quick app to show all the available InputScopes and automatically set the selected one on a TextBox. This gives you a feel for how many there are and what layout comes up when set. Here is what it looks like along with a link to the source:<\/p>\n<p><a href=\"https:\/\/whiskeyandcode.com\/downloads\/InputScopes.zip\">Download the source<\/a>.<\/p>\n<p><img src=\"https:\/\/whiskeyandcode.com\/images\/InputScope%20Sample%20Application_thumb.png\" alt=\"InputScope Sample Application\" title=\"InputScope Sample Application\"><\/p>\n<h2 id=\"common-inputscopes\">Common InputScopes<\/h2>\n<p>Now that you know how to set them here are some of the more useful InputScopes:<\/p>\n<h3 id=\"default\">Default<\/h3>\n<p><img src=\"https:\/\/whiskeyandcode.com\/images\/Default%20InputScope_thumb.png\" alt=\"Default InputScope\" title=\"Default InputScope\"><\/p>\n<p>This is the default InputScope when no input scope is specified. Auto-capitalize first letter of sentence. The app can show app specific text suggestions. Layout: Standard QWERTY layout.<\/p>\n<h3 id=\"number\">Number<\/h3>\n<p><img src=\"https:\/\/whiskeyandcode.com\/images\/Number%20InputScope_thumb.png\" alt=\"Number InputScope\" title=\"Number InputScope\"><\/p>\n<p>When all you&rsquo;re looking for is basic number entry. All features like auto-capitalize are turned off. Layout: the first symbol page of the standard QWERTY layout.<\/p>\n<h3 id=\"text\">Text<\/h3>\n<p><img src=\"https:\/\/whiskeyandcode.com\/images\/Text%20InputScope_thumb.jpg\" alt=\"Text InputScope\" title=\"Text InputScope\"><\/p>\n<p>When the user is typing standard text and can benefit from the full range of typing intelligence features:<\/p>\n<ul>\n<li>Text suggestions (while typing and when tapping on a word)<\/li>\n<li>Auto-correction<\/li>\n<li>Auto-Apostrophe (English)<\/li>\n<li>Auto-Accent<\/li>\n<li>Auto-capitalize first letter of sentence<\/li>\n<\/ul>\n<p>Layout: Text layout and access to letters, numbers, symbols and ASCII based emoticons + text suggestions.<\/p>\n<p>Example fields: email subject and body, OneNote notes, appointment subject and notes, Word document, etc.<\/p>\n<h3 id=\"chat\">Chat<\/h3>\n<p><img src=\"https:\/\/whiskeyandcode.com\/images\/Chat%20InputScope_thumb.jpg\" alt=\"Chat InputScope\" title=\"Chat InputScope\"><\/p>\n<p>The user is expected to type text using standard words as well as slang and abbreviations and can benefit from some of the typing intelligence features:<\/p>\n<ul>\n<li>Text suggestions (while typing and when tapping on a word)<\/li>\n<li>Auto-Apostrophe (English)<\/li>\n<li>Auto-Accent<\/li>\n<li>Auto-capitalize first letter of sentence<\/li>\n<\/ul>\n<p>Layout: Chat layout and access to letters, numbers, symbols and rich MSN like emoticons + text suggestions.\nExample fields: SMS, IM, Communicator, Twitter client, Facebook client, etc.<\/p>\n<h3 id=\"url\">Url<\/h3>\n<p><img src=\"https:\/\/whiskeyandcode.com\/images\/Url%20InputScope_thumb.png\" alt=\"Url InputScope\" title=\"Url InputScope\"><\/p>\n<p>The user is expected to type a URL. All auto-correct features are turned off. Layout: Web layout with <code>.com<\/code> and <code>go<\/code> key<\/p>\n<p>For a complete list of InputScopes supported in Windows Phone 7 check out this MSDN link: <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.windows.input.inputscopenamevalue(v=vs.95).aspx\">InputScopeNameValue Enumeration<\/a>.<\/p>\n<h3 id=\"in-conclusion\">In Conclusion<\/h3>\n<p>As you&rsquo;re writing your applications don&rsquo;t forget about InputScope, it&rsquo;ll give it just that much more polish and can really make a difference in usability.<\/p>","category":{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/categories\/windows-phone\/","term":"Windows Phone","label":"Windows Phone"}}},{"title":"Content from \u2018MIX10 - An Introduction to Developing Applications for Microsoft Silverlight\u2019","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/content-from-mix10-an-introduction-to-developing-applications-for-microsoft-silverlight\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/content-from-mix10-an-introduction-to-developing-applications-for-microsoft-silverlight\/","updated":"2026-10-18T02:41:51+00:00","published":"2010-03-23T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"I promised someone at the end of my talk that I&rsquo;d post my code and slides and while I&rsquo;m lagging a little behind I&rsquo;ve finally bundled them up and made them available for download here:\nSlides + Code\nAlso, as a small note I&rsquo;m slowly working this blog over to have a &ldquo;Windows Phone 7 Design Series&rdquo; look and feel, not sure how well the dark background and light text is going to carry over or how well my design kung fu will stack up but here goes.","content":"<p>I promised someone at the end of my talk that I&rsquo;d post my code and slides and while I&rsquo;m lagging a little behind I&rsquo;ve finally bundled them up and made them available for download here:<\/p>\n<p><a href=\"https:\/\/whiskeyandcode.com\/downloads\/YouAreHere.zip\">Slides + Code<\/a><\/p>\n<p>Also, as a small note I&rsquo;m slowly working this blog over to have a &ldquo;Windows Phone 7 Design Series&rdquo; look and feel, not sure how well the dark background and light text is going to carry over or how well my design kung fu will stack up but here goes.<\/p>\n<p><strong>UPDATE #1:<\/strong> I&rsquo;m also including the actual session itself here for your viewing pleasure. You can either watch it below or <a href=\"http:\/\/live.visitmix.com\/MIX10\/Sessions\/CL15\">directly on the MIX website<\/a>.<\/p>\n<p><strong>UPDATE #2:<\/strong> Several people have asked me for sample code to the solution that has a Windows Phone and Silverlight desktop application both consuming the same Class Library. Well, <a href=\"https:\/\/whiskeyandcode.com\/downloads\/TwoScreenApp.zip\">here it is for your downloading pleasure<\/a>.<\/p>\n<p><object data=\"data:application\/x-silverlight-2,\" type=\"application\/x-silverlight-2\"\nwidth=\"640\" height=\"360\">\n<param name=\"source\" value=\"http:\/\/live.visitmix.com\/ClientBin\/players\/VideoPlayer2009_03_27.xap\" \/>\n<param name=\"initParams\" value=\"m=http:\/\/ecn.channel9.msdn.com\/o9\/mix\/10\/wmv\/CL15.wmv,autostart=false,autohide=true,showembed=true, thumbnail=http:\/\/live.visitmix.com\/Skins\/MIX10\/Styles\/images\/DefaultPlayerBackground.png, postid=0\" \/>\n<param name=\"background\" value=\"#00FFFFFF\" \/>\n<a href=\"http:\/\/go.microsoft.com\/fwlink\/?LinkID=124807\">\n<img src=\"http:\/\/go.microsoft.com\/fwlink\/?LinkId=108181\" alt=\"Get Microsoft Silverlight\">\n<\/a>\n<\/object><\/p>","category":{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/categories\/silverlight\/","term":"Silverlight","label":"Silverlight"}}},{"title":"An Introduction to Developing Applications for Microsoft Silverlight at MIX10","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/an-introduction-to-developing-applications-for-microsoft-silverlight-mix10\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/an-introduction-to-developing-applications-for-microsoft-silverlight-mix10\/","updated":"2026-10-18T02:41:51+00:00","published":"2010-03-15T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"A quick heads up for anyone that saw my upcoming talk at MIX10. I&rsquo;m super excited (why do normal excited when you can be super excited!) to show everyone the basics of Silverlight so people can begin creating rockstar web and Windows Phone applications.","content":"<p>A quick heads up for anyone that saw my upcoming talk at MIX10. I&rsquo;m super excited (why do normal excited when you can be <em>super<\/em> excited!) to show everyone the basics of Silverlight so people can begin creating rockstar web and Windows Phone applications. Speaking of the basics I want to share for anyone that did a Bing search wondering who this Shawn Oster fellow is and what his talk is really about.<\/p>\n<p>My talk, <a href=\"http:\/\/live.visitmix.com\/MIX10\/Sessions\/CL15\">An Introduction to Developing Applications for Microsoft Silverlight<\/a>, really is an introduction, a 101. Maybe you are a HTML\/JavaScript ninja, perhaps you&rsquo;re just starting out, maybe you decided hand tuning assembly had lost its luster, whatever reason if you&rsquo;re a blank Silverlight slate then this is the talk for you. On the other hand if you know about this crazy concept called XAML or have the basics of wiring up event handlers and doing a little data binding then this talk is definitely not for you.<\/p>\n<p>If you&rsquo;re hoping for some Windows Phone love then you don&rsquo;t have to wait too much longer, Mike Harsh and Peter Torr lay down all the Windows Phone specific goods for you in the talks following mine. Think of my talk as a primer for those that need a quick intro to some of the concepts they&rsquo;ll be seeing later.<\/p>\n<p>MIX is an awesome, information-packed developer\/designer lovefest and I&rsquo;d hate for you to miss out on another track having to sit through 101 information.<\/p>","category":[{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/categories\/code\/","term":"Code","label":"Code"}},{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/tags\/silverlight\/","term":"Silverlight","label":"Silverlight"}},{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/tags\/mix\/","term":"MIX","label":"MIX"}}]},{"title":"Getting Excited for MIX10","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/getting-excited-for-mix10\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/getting-excited-for-mix10\/","updated":"2026-10-18T02:41:51+00:00","published":"2010-02-12T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"MIX is by far my favorite Microsoft event, and not just because it&rsquo;s in Las Vegas. It&rsquo;s the mix of designers and developers, about learning cool stuff and just getting the creative juices flowing. Whether I&rsquo;m there in person or just watching the keynote via the web it has a rejuvenating effect on me and gets me excited to make cool stuff.","content":"<p><a href=\"http:\/\/live.visitmix.com\/\">MIX<\/a> is by far my favorite Microsoft event, and not just because it&rsquo;s in <a href=\"http:\/\/www.bing.com\/search?q=las+vegas\">Las Vegas<\/a>. It&rsquo;s the mix of designers and developers, about learning cool stuff and just getting the creative juices flowing. Whether I&rsquo;m there in person or just watching the keynote via the web it has a rejuvenating effect on me and gets me excited to make cool stuff.<\/p>\n<p>This year I&rsquo;m also excited for two reasons: first it looks like I&rsquo;ll get to speak (link to my talk to be posted once it&rsquo;s on the schedule) and two because as a gadget and code nerd we get to learn about <a href=\"http:\/\/live.visitmix.com\/News\/Windows-Phone-at-MIX10\">the development story of the upcoming Windows Phone<\/a>! Per the MIX website a few weeks back:<\/p>\n<blockquote>\n<p>Yes, at MIX10 you&rsquo;ll learn about developing applications and games for the next generation of Windows Phone. Yes, we&rsquo;ll have Phone sessions, and we can&rsquo;t say more&hellip; yet.<\/p>\n<\/blockquote>\n<p>One thing I think people outside Microsoft don&rsquo;t realize, at least I know I didn&rsquo;t before working here, is that there is so much going on inside the company and we get so focused on whatever our project is that announcements like this are just as exciting for people inside the company as out!<\/p>\n<p><a href=\"https:\/\/whiskeyandcode.com\/images\/Mix10_SeeYou_blk_240.jpg\"><img src=\"https:\/\/whiskeyandcode.com\/images\/Mix10_SeeYou_blk_240_thumb.jpg\" alt=\"Mix10_SeeYou_blk_240\" title=\"Mix10_SeeYou_blk_240\"><\/a><\/p>"},{"title":"Silverlight TreeView Connecting Lines And Blend 3 Support for HierarchicalDataTemplates","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/silverlight-treeview-connecting-lines-and-blend-3-support-for-hierarchicaldatatemplates\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/silverlight-treeview-connecting-lines-and-blend-3-support-for-hierarchicaldatatemplates\/","updated":"2026-10-18T02:41:51+00:00","published":"2009-08-26T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"The July 2009 release of the Silverlight Toolkit has a bunch of great things in it but a few of them require just a little digging. A common request in the forums and on CodePlex is how to add connecting lines to the standard TreeView.","content":"<p>The <a href=\"http:\/\/www.codeplex.com\/Silverlight\/Release\/ProjectReleases.aspx\">July 2009 release of the Silverlight Toolkit<\/a> has a bunch of great things in it but a few of them require just a little digging. A common request in the forums and on CodePlex is <a href=\"http:\/\/silverlight.codeplex.com\/WorkItem\/View.aspx?WorkItemId=851\">how to add connecting lines to the standard TreeView<\/a>. Well, thanks to TreeViewExtensions and a pre-built template it&rsquo;s now an easy request to fulfill.<\/p>\n<p>I&rsquo;m going to show you how to add connecting lines using Blend 3 but it&rsquo;s not a requirement. Grab a copy of <a href=\"http:\/\/www.microsoft.com\/expression\/\">Expression Studio 3<\/a> if you don&rsquo;t already have Blend installed. There were a lot of great enhancements with the last release so I encourage you to give it a go.<\/p>\n<h2 id=\"prerequisites\">Prerequisites<\/h2>\n<ol>\n<li>Make sure you&rsquo;ve installed the July 2009 release of the Silverlight Toolkit<\/li>\n<li>Start a new Silverlight project in Blend 3<\/li>\n<li>While you <strong>could<\/strong> start by dragging a TreeView from the Asset pane onto the design surface I want to show off Blend&rsquo;s support for sample data and editing the HierarchialDataTemplate.<\/li>\n<\/ol>\n<h2 id=\"define-sample-data\">Define Sample Data<\/h2>\n<p>One of the more annoying things when trying a do a little research into how you can tweak a control is having to come up with some kind of mock data to work with, especially when working with a TreeView because of its hierarchical nature. Blend 3 introduced a huge time-saving feature, Sample Data, that we&rsquo;ll take advantage of.<\/p>\n<p>For this example I want to end up with a common TreeView UI pattern, an icon followed by some text, similar to a basic file browser. With those requirements in mind lets create some sample data.<\/p>\n<ol>\n<li>\n<p>Switch to the Data panel<\/p>\n<\/li>\n<li>\n<p>Click on the &lsquo;Add sample data source&rsquo; icon (circled below) and choose &lsquo;Define New Sample Data&rsquo;<\/p>\n<p><a href=\"https:\/\/whiskeyandcode.com\/images\/SilverlightTreeViewConnectingLines.png\"><img src=\"https:\/\/whiskeyandcode.com\/images\/SilverlightTreeViewConnectingLines_thumb.png\" alt=\"Define New Sample Data\" title=\"Define New Sample Data\"><\/a><\/p>\n<\/li>\n<li>\n<p>Go with all the defaults and click OK<\/p>\n<\/li>\n<li>\n<p>Presto, magic sample data!<\/p>\n<\/li>\n<\/ol>\n<p>At this point you can drag the SampleDataSource onto the design surface and Blend will create a ListBox with fields properly bound to the control and fully interactive sample data. Very useful but we need to do a just a little more tweaking to get it where we want it.<\/p>\n<p>Change the property type of Property1 to an Image and Property2 to a String. You do this via the property type dialog accessed by clicking on the icon to the right of property name (circled below).<\/p>\n<p><a href=\"https:\/\/whiskeyandcode.com\/images\/SilverlightTreeViewConnectingLines_3.png\"><img src=\"https:\/\/whiskeyandcode.com\/images\/SilverlightTreeViewConnectingLines_thumb_3.png\" alt=\"image\" title=\"image\"><\/a><\/p>\n<p>Almost there. We now have an image and some text but it&rsquo;s missing that hierarchical nature. Easy enough to fix. Click on the drop down to the right of the Collection and click \u201cConvert to Hierarchical Collection\u201d:<\/p>\n<p><a href=\"https:\/\/whiskeyandcode.com\/images\/SilverlightTreeViewConnectingLines_4.png\"><img src=\"https:\/\/whiskeyandcode.com\/images\/SilverlightTreeViewConnectingLines_thumb_4.png\" alt=\"image\" title=\"image\"><\/a><\/p>\n<p>At this point you&rsquo;ll have a collection that contains a collection that contains a collection that\u2026 you get my drift. Grab the first Collection underneath SampleDataSource and drag it onto the Blend design surface and watch the magic happen!<\/p>\n<p>You&rsquo;ll end up with something like this:<\/p>\n<p><a href=\"https:\/\/whiskeyandcode.com\/images\/SilverlightTreeViewConnectingLines_5.png\"><img src=\"https:\/\/whiskeyandcode.com\/images\/SilverlightTreeViewConnectingLines_thumb_5.png\" alt=\"image\" title=\"image\"><\/a><\/p>\n<p>Pretty awesome considering you didn&rsquo;t have to create a single mock object, mess with any XAML or write any code.<\/p>\n<h2 id=\"customizing-the-hierarchialdatatemplate-in-blend\">Customizing the HierarchialDataTemplate in Blend<\/h2>\n<p>OK, now that the rush of excitement has worn off (if it hasn&rsquo;t don&rsquo;t worry, just take a few deep breaths, take a walk and come back when you&rsquo;ve got your heart rate under control) the harsh reality creeps in that this doesn&rsquo;t look exactly like your basic file browser. Image is a bit big and the text is underneath it the icon.<\/p>\n<p>Easy enough to fix:<\/p>\n<ol>\n<li>Select the TreeView<\/li>\n<li>There are at least three ways to navigate to the Edit Current Template menu but I find the fastest is clicking on the TreeView breadcrumb underneath the MainPage.xaml tab (illustrated below)\n<a href=\"https:\/\/whiskeyandcode.com\/images\/SilverlightTreeViewConnectingLines_13.png\"><img src=\"https:\/\/whiskeyandcode.com\/images\/SilverlightTreeViewConnectingLines_thumb_13.png\" alt=\"image\" title=\"image\"><\/a><\/li>\n<\/ol>\n<p>At this point you have a very simple template to work with, a basic StackPanel containing an Image and TextBlock<\/p>\n<p><a href=\"https:\/\/whiskeyandcode.com\/images\/SilverlightTreeViewConnectingLines_7.png\"><img src=\"https:\/\/whiskeyandcode.com\/images\/SilverlightTreeViewConnectingLines_thumb_7.png\" alt=\"image\" title=\"image\"><\/a><\/p>\n<p>Go ahead and tweak the template into something a little more like what you&rsquo;d expect from a file browser:<\/p>\n<ol>\n<li>Change the orientation of the StackPanel to Horizontal<\/li>\n<li>Change the Width and Height of the Image to 16 x 16<\/li>\n<li>Change the VerticalAlignment of the TextBlock to Center<\/li>\n<\/ol>\n<p>Now we have something much more useful:<\/p>\n<p><a href=\"https:\/\/whiskeyandcode.com\/images\/SilverlightTreeViewConnectingLines_8.png\"><img src=\"https:\/\/whiskeyandcode.com\/images\/SilverlightTreeViewConnectingLines_thumb_8.png\" alt=\"image\" title=\"image\"><\/a><\/p>\n<p>(I changed my sample data generation on the string to only create one word with a maximum of 12 characters)<\/p>\n<h3 id=\"where-are-those-connecting-lines\">Where Are Those Connecting Lines?<\/h3>\n<p>I know what you&rsquo;re thinking, I brought you all this way, are we ever going to get to the connecting lines part? Well, the grand revel is here!<\/p>\n<ol>\n<li>Add a reference to System.Windows.Controls.Toolkit (if you went with the default install it should be in C:\\Program Files\\Microsoft SDKs\\Silverlight\\v3.0\\Toolkit\\Jul09\\Bin)<\/li>\n<li>Download <a href=\"http:\/\/s3.amazonaws.com:80\/enginefour\/TreeViewConnectingLines.xaml\">TreeViewConnectingLines.xaml<\/a> and add it to your project<\/li>\n<li>Switch to the Resources panel and expand TreeViewConnectingLines.xaml, it&rsquo;ll look like this:\n<a href=\"https:\/\/whiskeyandcode.com\/images\/SilverlightTreeViewConnectingLines_9.png\"><img src=\"https:\/\/whiskeyandcode.com\/images\/SilverlightTreeViewConnectingLines_thumb_9.png\" alt=\"image\" title=\"image\"><\/a><\/li>\n<li>There is a style for both the TreeView itself and the TreeViewItems that it contains.<\/li>\n<li>Drag ConnectingLinesTreeView onto the TreeView and when prompted select Select property on [TreeView] Style\n<a href=\"https:\/\/whiskeyandcode.com\/images\/SilverlightTreeViewConnectingLines_10.png\"><img src=\"https:\/\/whiskeyandcode.com\/images\/SilverlightTreeViewConnectingLines_thumb_10.png\" alt=\"image\" title=\"image\"><\/a><\/li>\n<li>Switch to the Properties panel for the TreeView<\/li>\n<li>Scroll down to ItemContainerStyle (in Miscellaneous section)<\/li>\n<li>Click the Advanced property button to the right of the property (circled below)\n<a href=\"https:\/\/whiskeyandcode.com\/images\/SilverlightTreeViewConnectingLines_11.png\"><img src=\"https:\/\/whiskeyandcode.com\/images\/SilverlightTreeViewConnectingLines_thumb_11.png\" alt=\"image\" title=\"image\"><\/a><\/li>\n<li>Select Local Resource -&gt; ConnectingLinesTreeViewItem<\/li>\n<\/ol>\n<p>And there you go! You now have connecting lines, with a plus\/plus icon showing expansion state. It even shows inside of Blend so you see exactly what you get but it&rsquo;s more fun to run it and see it in all its connecting line glory!<\/p>\n<p><a href=\"https:\/\/whiskeyandcode.com\/images\/SilverlightTreeViewConnectingLines_12.png\"><img src=\"https:\/\/whiskeyandcode.com\/images\/SilverlightTreeViewConnectingLines_thumb_12.png\" alt=\"image\" title=\"image\"><\/a><\/p>\n<h2 id=\"source\">Source<\/h2>\n<p><strong>UPDATE:<\/strong> I&rsquo;ve been asked in the comments to provide the source so without further ado get it here:<\/p>\n<p><a href=\"https:\/\/whiskeyandcode.com\/downloads\/TreeViewConnectingLines.zip\"><strong>Connecting Lines Source<\/strong><\/a><\/p>\n<h2 id=\"epilogue\">Epilogue<\/h2>\n<p>To be honest I could have just started with adding the connecting lines and you&rsquo;d be on your way but I really wanted to show off sample data for TreeView, converting that sample data into a hierarchy and editing the HierarchicalDataTemplate in Blend 3.<\/p>","category":{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/categories\/silverlight\/","term":"Silverlight","label":"Silverlight"}}},{"title":"Your Inner Remembrance One","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/your-inner-remembrance-one\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/your-inner-remembrance-one\/","updated":"2026-10-18T02:41:51+00:00","published":"2009-06-18T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"Part of my personal daily rounds is catching up on all the gaming news which means hitting up Engadget and Joystiq. I was reading a recent tidbit about how new XBox 360&rsquo;s are starting to show up with both the Jasper motherboard and 512MB of internal memory, something some of you may or may not be as excited about as I am.","content":"<p>Part of my personal daily rounds is catching up on all the gaming news which means hitting up <a href=\"http:\/\/www.engadget.com\/\">Engadget<\/a> and <a href=\"http:\/\/www.joystiq.com\/\">Joystiq<\/a>. I was reading a <a href=\"http:\/\/www.engadget.com\/2009\/06\/17\/xbox-360-jasper-motherboard-with-512mb-storage-hitting-us-stores\/\">recent tidbit<\/a> about how new XBox 360&rsquo;s are starting to show up with both the Jasper motherboard and 512MB of internal memory, something some of you may or may not be as excited about as I am.<\/p>\n<p>The part that really caught my eye though was when I did a <a href=\"http:\/\/www.bing.com\">Bing<\/a> search for &ldquo;xbox jasper&rdquo;, in an effort to catch up on my XBox motherboard goodness, and stumbled across the exact same Engadget article on another site with some slightly different phrasing. This isn&rsquo;t surprising in itself since it&rsquo;s a pretty common ad trap to scrap content from a popular website and surround it with ads hoping people will click on them but the fun part was this site tried to make the content more unique by running it through a thesaurus. Most of it ended up sounding like a drunk pedantic linguistics professor muttering to himself but here is the choice bit that had me rolling on the floor (ok, chuckling softly to myself like a crazed madman but you get the idea):<\/p>\n<p>Original:<\/p>\n<blockquote>\n<p>That&rsquo;s twice the size of the old one, giving the equivalent of a 512MB internal memory unit.<\/p>\n<\/blockquote>\n<p>New And Improved!<\/p>\n<blockquote>\n<p>That&rsquo;s two times the bigness of the rich person, giving the tantamount of a 512MB inner remembrance one.<\/p>\n<\/blockquote>"},{"title":"Adding Silverlight Toolkit Controls to the Visual Studio and Blend Toolbox","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/adding-silverlight-toolkit-controls-to-the-visual-studio-and-blend-toolbox\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/adding-silverlight-toolkit-controls-to-the-visual-studio-and-blend-toolbox\/","updated":"2026-10-18T02:41:51+00:00","published":"2009-02-04T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"Now that title is a mouth-full. I&rsquo;ve seen a few questions in the Silverlight.net forums asking how to get the Silverlight Toolkit controls into the toolbox\/asset library of Visual Studio 2008 and\/or Expression Blend 2. There are a bunch of great posts scattered among the tubes on how to do this but I wanted to explain both Visual Studio 2008 and Blend 2 in one post.","content":"<p>Now that title is a mouth-full. I&rsquo;ve seen a few questions in the <a href=\"http:\/\/silverlight.net\/forums\/35.aspx\">Silverlight.net forums<\/a> asking how to get the <a href=\"http:\/\/www.codeplex.com\/Silverlight\">Silverlight Toolkit<\/a> controls into the toolbox\/asset library of Visual Studio 2008 and\/or <a href=\"http:\/\/www.microsoft.com\/expression\/products\/Overview.aspx?key=blend\">Expression Blend 2<\/a>. There are a bunch of great posts scattered among the tubes on how to do this but I wanted to explain both Visual Studio 2008 and Blend 2 in one post. Plus it&rsquo;ll segue nicely into an upcoming post :)<\/p>\n<h2 id=\"download-the-silverlight-toolkit\">Download the Silverlight Toolkit<\/h2>\n<ol>\n<li>Download the latest release of the <a href=\"http:\/\/www.codeplex.com\/Silverlight\/Release\/ProjectReleases.aspx?ReleaseId=19172\">Silverlight Toolkit<\/a> (December 2008 as of this post).<\/li>\n<li>Unzip to a folder of your liking (I use the highly imaginative <code>C:\\Source\\Silverlight Toolkit December 2008<\/code>).<\/li>\n<\/ol>\n<h2 id=\"adding-to-the-visual-studio-2008-toolbox\">Adding to the Visual Studio 2008 Toolbox<\/h2>\n<p>You can add the controls to any tab in the Toolbox you like, for this example I&rsquo;m going to create a new tab, Silverlight Toolkit.<\/p>\n<ol>\n<li>Right-click anywhere in the Toolbox and select <strong>Add Tab<\/strong>, name it Silverlight Toolkit.<\/li>\n<li>Right-click in the empty space of the Silverlight Toolkit group and select <strong>Choose Items<\/strong>.<\/li>\n<li>Select the Silverlight Components tab.<\/li>\n<li>Click Browse and browse to Binaries folder, adding <code>Microsoft.Windows.Controls<\/code>, <code>Microsoft.Windows.Controls.Input<\/code> and <code>Microsoft.Windows.Controls.DataVisualization<\/code>.<\/li>\n<li>The controls will now appear in your Toolbox.<\/li>\n<\/ol>\n<p><img src=\"https:\/\/whiskeyandcode.com\/images\/Silverlight%20Toolkit%20controls%20in%20Visual%20Studio%202008%20Toolbox.png\" alt=\"Silverlight Toolkit controls in Visual Studio 2008 toolbox\" title=\"Silverlight Toolkit controls in Visual Studio 2008 toolbox\"><\/p>\n<h2 id=\"adding-to-expression-blend-2-asset-library\">Adding to Expression Blend 2 Asset Library<\/h2>\n<p>Adding controls to Blend is even easier, though you do have to repeat this process for each new project. Also because making controls available in Blend requires you to add references to your project, thus increasing your download size, you should only add references to the assemblies you need. Bit of a chicken and egg issue. To help you decide which assemblies to add I included a breakdown of which controls are in what assembly after these instructions.<\/p>\n<ol>\n<li>\n<p>In your Project pane right-click on References, select Add Reference\u2026.<\/p>\n<\/li>\n<li>\n<p>Add references to Microsoft.Windows.Controls, Microsoft.Windows.Controls.DataVisualization, Microsoft.Windows.Controls.Input.<\/p>\n<p><img src=\"https:\/\/whiskeyandcode.com\/images\/Blend%20Project%20Pane.PNG\" alt=\"Blend 2 Project Pane\" title=\"Blend 2 Project Pane\"><\/p>\n<\/li>\n<li>\n<p>The controls will now appear in the Custom Controls section of the Asset Library.<\/p>\n<\/li>\n<\/ol>\n<p><img src=\"https:\/\/whiskeyandcode.com\/images\/Blend%202%20Asset%20Library.PNG\" alt=\"Blend 2 Asset Library\" title=\"Blend 2 Asset Library\"><\/p>\n<h2 id=\"whats-in-each-assembly\">What&rsquo;s In Each Assembly?<\/h2>\n<p><code>Microsoft.Windows.Controls<\/code><\/p>\n<ul>\n<li>AutoCompleteBox<\/li>\n<li>DockPanel<\/li>\n<li>Expander<\/li>\n<li>HeaderedContentControl<\/li>\n<li>HeaderedItemsControls<\/li>\n<li>Label<\/li>\n<li>TreeView<\/li>\n<li>TreeViewItem<\/li>\n<li>Viewbox<\/li>\n<li>WrapPanel<\/li>\n<\/ul>\n<p><code>Microsoft.Windows.Controls.Input<\/code><\/p>\n<ul>\n<li>ButtonSpinner<\/li>\n<li>NumericUpDown<\/li>\n<\/ul>\n<p><code>Microsoft.Windows.Controls.DataVisualization<\/code><\/p>\n<ul>\n<li>Charting (with associated Axis, DataPoint and Series).<\/li>\n<\/ul>\n<h2 id=\"getting-support-offering-feedback\">Getting Support, Offering Feedback<\/h2>\n<p>As always the best place to get support for the Silverlight Toolkit is to post in <a href=\"http:\/\/silverlight.net\/forums\/35.aspx\">our forum on Silverlight.net<\/a>. If you have a feature request or bug please file it in our <a href=\"http:\/\/www.codeplex.com\/Silverlight\/WorkItem\/List.aspx\">Issue Tracker<\/a> and get some votes behind it. We look carefully at those numbers when we decide how to prioritize the bug fixes.<\/p>\n<p>(Updated to include warning about adding assemblies you don&rsquo;t need in Blend and what controls are in each assembly, plus fixed the title tag on a few images)<\/p>","category":[{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/categories\/code\/","term":"Code","label":"Code"}},{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/tags\/silverlight\/","term":"Silverlight","label":"Silverlight"}},{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/tags\/ui\/","term":"Ui","label":"Ui"}},{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/tags\/visual-studio\/","term":"Visual Studio","label":"Visual Studio"}},{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/tags\/blend\/","term":"Blend","label":"Blend"}}]},{"title":"Working with Units of Measure in a NumericUpDown","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/working-with-units-of-measure-in-a-numericupdown\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/working-with-units-of-measure-in-a-numericupdown\/","updated":"2026-10-18T02:41:51+00:00","published":"2008-12-11T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"One of the great controls released with the Silverlight Toolkit is the NumericUpDown. Sure it may seem like just a basic textbox that allows user input with the added glory of a spinner that makes it easy to nudge values up or down with a click, which in and of itself is a great benefit, but there is also some lesser known plumbing that allows users to easily extend this control to provide some great user experiences.","content":"<p>One of the great controls released with the <a href=\"http:\/\/www.codeplex.com\/Silverlight\">Silverlight Toolkit<\/a> is the NumericUpDown. Sure it may seem like just a basic textbox that allows user input with the added glory of a spinner that makes it easy to nudge values up or down with a click, which in and of itself is a great benefit, but there is also some lesser known plumbing that allows users to easily extend this control to provide some great user experiences.<\/p>\n<p>One of my favorite user experiences is the way the UpDowns, or spinners as some call them, work in Microsoft Word when you&rsquo;re adjusting your margins. The first great thing is that you see a suffix indicating your current unit of measure. The second, and cooler, thing is if your default measurement unit is inches and you type 10mm it&rsquo;ll automatically convert 10 millimeters into inches for you, which I think is brilliant especially considering how often UpDowns are used to represent measurements.<\/p>\n<p><a href=\"https:\/\/whiskeyandcode.com\/images\/CreatingaMeasurementUpDownfromaNumericUp_image_8.png\"><img src=\"https:\/\/whiskeyandcode.com\/images\/CreatingaMeasurementUpDownfromaNumericUp_image_8_thumb.png\" alt=\"image\" title=\"image\"><\/a><\/p>\n<p>Using two handy virtuals in NumericUpDown, FormatValue and ParseValue, the same functionality can be created in Silverlight. I show you how to get started and leave the monkey work of length conversion to you :)<\/p>\n<h2 id=\"step-1-reference-the-silverlight-toolkit\">Step 1: Reference the Silverlight Toolkit<\/h2>\n<p>The first step is to download the <a href=\"http:\/\/www.codeplex.com\/Silverlight\">Silverlight Toolkit<\/a> if you haven&rsquo;t already, unzip it, create a new Silverlight Application project (I called mine PageLayout because I was inspired by the Page Layout section in Word) and add a reference to Microsoft.Windows.Controls.Input.<\/p>\n<p><a href=\"https:\/\/whiskeyandcode.com\/images\/CreatingaMeasurementUpDownfromaNumericUp_2.png\"><img src=\"https:\/\/whiskeyandcode.com\/images\/CreatingaMeasurementUpDownfromaNumericUp_2_thumb.png\" alt=\"Microsoft.Windows.Controls.Input Reference\" title=\"Microsoft.Windows.Controls.Input Reference\"><\/a><\/p>\n<h2 id=\"step-2-create-the-lengthupdown-class\">Step 2: Create The LengthUpDown Class<\/h2>\n<p>Do the usual right-click Add Class dance and name it LengthUpDown.cs. We want to descend LengthUpDown from NumericUpDown so add a using statement referencing the toolkit namespace: Microsoft.Windows.Controls. At this point you should have:<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><span class=\"lnt\">2\n<\/span><span class=\"lnt\">3\n<\/span><span class=\"lnt\">4\n<\/span><span class=\"lnt\">5\n<\/span><span class=\"lnt\">6\n<\/span><span class=\"lnt\">7\n<\/span><span class=\"lnt\">8\n<\/span><span class=\"lnt\">9\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-csharp\" data-lang=\"csharp\"><span class=\"line\"><span class=\"cl\"><span class=\"k\">using<\/span> <span class=\"nn\">Microsoft.Windows.Controls<\/span><span class=\"p\">;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"k\">namespace<\/span> <span class=\"nn\">PageLayout<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"kd\">public<\/span> <span class=\"k\">class<\/span> <span class=\"nc\">LengthUpDown<\/span> <span class=\"p\">:<\/span> <span class=\"n\">NumericUpDown<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><h2 id=\"step-3-formatvalue--parsevalue\">Step 3: FormatValue &amp; ParseValue<\/h2>\n<p>So far everything has been prep, let&rsquo;s do something interesting. UpDownBase, the class NumericUpDown base derives from, exposes two useful virtual methods: FormatValue and ParseValue.<\/p>\n<p>FormatValue is responsible for formatting the actual Value as a string for the user. It is purely for display purposes so you can format it however you like. You could return the word \u201cthree\u201d for the value 3 or in our case append a suffix representing the current measurement unit, such as \u201cmm\u201d.<\/p>\n<p>ParseValue goes the other direction, it takes the user-entered string and converts it back to a double. This is where you could for example take the word \u201cthree\u201d and convert it to 3 or in our case scan the string to see if there is a unit suffix such as mm, cm, pt or px and do the appropriate conversion before returning the value.<\/p>\n<p>The basic skeleton for our LengthUpDown starts something like this:<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\"> 1\n<\/span><span class=\"lnt\"> 2\n<\/span><span class=\"lnt\"> 3\n<\/span><span class=\"lnt\"> 4\n<\/span><span class=\"lnt\"> 5\n<\/span><span class=\"lnt\"> 6\n<\/span><span class=\"lnt\"> 7\n<\/span><span class=\"lnt\"> 8\n<\/span><span class=\"lnt\"> 9\n<\/span><span class=\"lnt\">10\n<\/span><span class=\"lnt\">11\n<\/span><span class=\"lnt\">12\n<\/span><span class=\"lnt\">13\n<\/span><span class=\"lnt\">14\n<\/span><span class=\"lnt\">15\n<\/span><span class=\"lnt\">16\n<\/span><span class=\"lnt\">17\n<\/span><span class=\"lnt\">18\n<\/span><span class=\"lnt\">19\n<\/span><span class=\"lnt\">20\n<\/span><span class=\"lnt\">21\n<\/span><span class=\"lnt\">22\n<\/span><span class=\"lnt\">23\n<\/span><span class=\"lnt\">24\n<\/span><span class=\"lnt\">25\n<\/span><span class=\"lnt\">26\n<\/span><span class=\"lnt\">27\n<\/span><span class=\"lnt\">28\n<\/span><span class=\"lnt\">29\n<\/span><span class=\"lnt\">30\n<\/span><span class=\"lnt\">31\n<\/span><span class=\"lnt\">32\n<\/span><span class=\"lnt\">33\n<\/span><span class=\"lnt\">34\n<\/span><span class=\"lnt\">35\n<\/span><span class=\"lnt\">36\n<\/span><span class=\"lnt\">37\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-csharp\" data-lang=\"csharp\"><span class=\"line\"><span class=\"cl\"><span class=\"k\">using<\/span> <span class=\"nn\">System<\/span><span class=\"p\">;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"k\">using<\/span> <span class=\"nn\">Microsoft.Windows.Controls<\/span><span class=\"p\">;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"k\">namespace<\/span> <span class=\"nn\">PageLayout<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"kd\">public<\/span> <span class=\"k\">class<\/span> <span class=\"nc\">LengthUpDown<\/span> <span class=\"p\">:<\/span> <span class=\"n\">NumericUpDown<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"cs\">\/\/\/<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"cs\">\/\/\/ Formats the value for display in the control.<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"cs\">\/\/\/<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"kd\">protected<\/span> <span class=\"kd\">override<\/span> <span class=\"kt\">string<\/span> <span class=\"n\">FormatValue<\/span><span class=\"p\">()<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"kt\">string<\/span> <span class=\"n\">suffix<\/span> <span class=\"p\">=<\/span> <span class=\"n\">DetermineMeasurementSuffix<\/span><span class=\"p\">();<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">return<\/span> <span class=\"k\">base<\/span><span class=\"p\">.<\/span><span class=\"n\">FormatValue<\/span><span class=\"p\">()<\/span> <span class=\"p\">+<\/span> <span class=\"n\">suffix<\/span><span class=\"p\">;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"kd\">private<\/span> <span class=\"kt\">string<\/span> <span class=\"n\">DetermineMeasurementSuffix<\/span><span class=\"p\">()<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">throw<\/span> <span class=\"k\">new<\/span> <span class=\"n\">NotImplementedException<\/span><span class=\"p\">();<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"cs\">\/\/\/<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"cs\">\/\/\/ Parses the value the user entered and converts it to the<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"cs\">\/\/\/ correct value.<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"cs\">\/\/\/<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"kd\">protected<\/span> <span class=\"kd\">override<\/span> <span class=\"kt\">double<\/span> <span class=\"n\">ParseValue<\/span><span class=\"p\">(<\/span><span class=\"kt\">string<\/span> <span class=\"n\">text<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"kt\">double<\/span> <span class=\"n\">length<\/span> <span class=\"p\">=<\/span> <span class=\"n\">ConvertLength<\/span><span class=\"p\">(<\/span><span class=\"n\">text<\/span><span class=\"p\">);<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">return<\/span> <span class=\"n\">length<\/span><span class=\"p\">;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"kd\">private<\/span> <span class=\"kt\">double<\/span> <span class=\"n\">ConvertLength<\/span><span class=\"p\">(<\/span><span class=\"kt\">string<\/span> <span class=\"n\">text<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">throw<\/span> <span class=\"k\">new<\/span> <span class=\"n\">NotImplementedException<\/span><span class=\"p\">();<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><h2 id=\"step-4-length-conversion\">Step 4: Length Conversion<\/h2>\n<p>In an effort not to introduce too many concepts at once and to keep the code samples short I&rsquo;ve omitted all the actual conversion logic. In the next few days I&rsquo;ll post a fully working version that converts between common units of linear measure. If you&rsquo;re bored or ambitious go ahead and implement them, they&rsquo;re fairly easy for a limited number of measurement units. Here is a little peak at a fun little fluent-interface conversion class that I created (and that will be included in the upcoming project):<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><span class=\"lnt\">2\n<\/span><span class=\"lnt\">3\n<\/span><span class=\"lnt\">4\n<\/span><span class=\"lnt\">5\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-csharp\" data-lang=\"csharp\"><span class=\"line\"><span class=\"cl\"><span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">suffix<\/span> <span class=\"p\">!=<\/span> <span class=\"n\">String<\/span><span class=\"p\">.<\/span><span class=\"n\">Empty<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">LengthUnit<\/span> <span class=\"n\">fromUnit<\/span> <span class=\"p\">=<\/span> <span class=\"n\">SuffixToLengthUnit<\/span><span class=\"p\">(<\/span><span class=\"n\">suffix<\/span><span class=\"p\">);<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">return<\/span> <span class=\"k\">new<\/span> <span class=\"n\">ConvertLength<\/span><span class=\"p\">(<\/span><span class=\"n\">length<\/span><span class=\"p\">).<\/span><span class=\"n\">From<\/span><span class=\"p\">(<\/span><span class=\"n\">fromUnit<\/span><span class=\"p\">).<\/span><span class=\"n\">To<\/span><span class=\"p\">(<\/span><span class=\"n\">DefaultLengthUnit<\/span><span class=\"p\">);<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><h2 id=\"step-5-using-it\">Step 5: Using It<\/h2>\n<p>Once you&rsquo;ve implemented your conversion logic, hopefully in another class to maximize unit testing, then you&rsquo;ll want to actually use your new control. For my example I created the control directly in the project so it&rsquo;s easy to get it rocking in the application.<\/p>\n<p>Open the page.xaml and add the project&rsquo;s namespace to the XAML so you can use your new control and plop down an instance of it, leaving you with:<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\"> 1\n<\/span><span class=\"lnt\"> 2\n<\/span><span class=\"lnt\"> 3\n<\/span><span class=\"lnt\"> 4\n<\/span><span class=\"lnt\"> 5\n<\/span><span class=\"lnt\"> 6\n<\/span><span class=\"lnt\"> 7\n<\/span><span class=\"lnt\"> 8\n<\/span><span class=\"lnt\"> 9\n<\/span><span class=\"lnt\">10\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-xml\" data-lang=\"xml\"><span class=\"line\"><span class=\"cl\"><span class=\"nt\">&lt;UserControl<\/span> <span class=\"na\">x:Class=<\/span><span class=\"s\">&#34;PageLayout.Page&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">xmlns=<\/span><span class=\"s\">&#34;http:\/\/schemas.microsoft.com\/winfx\/2006\/xaml\/presentation&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">xmlns:x=<\/span><span class=\"s\">&#34;http:\/\/schemas.microsoft.com\/winfx\/2006\/xaml&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">xmlns:local=<\/span><span class=\"s\">&#34;clr-namespace:PageLayout&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">Width=<\/span><span class=\"s\">&#34;400&#34;<\/span> <span class=\"na\">Height=<\/span><span class=\"s\">&#34;300&#34;<\/span><span class=\"nt\">&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;Grid<\/span> <span class=\"na\">x:Name=<\/span><span class=\"s\">&#34;LayoutRoot&#34;<\/span> <span class=\"na\">Background=<\/span><span class=\"s\">&#34;White&#34;<\/span><span class=\"nt\">&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;local:LengthUpDown<\/span> <span class=\"na\">Value=<\/span><span class=\"s\">&#34;10&#34;<\/span> <span class=\"nt\">\/&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;\/Grid&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nt\">&lt;\/UserControl&gt;<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><p>Run the project and you should see a LengthUpDown looking control in the middle of the page.<\/p>\n<h2 id=\"step-6-the-next-step\">Step 6: The Next Step<\/h2>\n<p>As I mentioned I&rsquo;ll be posting a more completely control in the coming days but for now you have everything you need to add custom prefixes and suffixes to numeric values in your UpDown controls.<\/p>","category":[{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/tags\/code\/","term":"Code","label":"Code"}},{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/tags\/csharp\/","term":"Csharp","label":"Csharp"}},{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/tags\/xaml\/","term":"Xaml","label":"Xaml"}}]},{"title":"Dynamic Icons in the Silverlight TreeView","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/dynamic-icons-in-the-silverlight-treeview\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/dynamic-icons-in-the-silverlight-treeview\/","updated":"2026-10-18T02:41:51+00:00","published":"2008-11-07T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"A common question in the forums has been how to get dynamic icons in the Silverlight Toolkit TreeView and luckily there are quite a few options.\nThe Icon Before you can make the icon dynamic you need a place to put it. The basic idea is to create a HierarchicalDataTemplate and make room for an image:","content":"<p>A common question in the <a href=\"http:\/\/silverlight.net\/forums\/35.aspx\">forums<\/a> has been how to get dynamic icons in the <a href=\"http:\/\/www.codeplex.com\/Silverlight\">Silverlight Toolkit<\/a> TreeView and luckily there are quite a few options.<\/p>\n<h2 id=\"the-icon\">The Icon<\/h2>\n<p>Before you can make the icon dynamic you need a place to put it. The basic idea is to create a HierarchicalDataTemplate and make room for an image:<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\"> 1\n<\/span><span class=\"lnt\"> 2\n<\/span><span class=\"lnt\"> 3\n<\/span><span class=\"lnt\"> 4\n<\/span><span class=\"lnt\"> 5\n<\/span><span class=\"lnt\"> 6\n<\/span><span class=\"lnt\"> 7\n<\/span><span class=\"lnt\"> 8\n<\/span><span class=\"lnt\"> 9\n<\/span><span class=\"lnt\">10\n<\/span><span class=\"lnt\">11\n<\/span><span class=\"lnt\">12\n<\/span><span class=\"lnt\">13\n<\/span><span class=\"lnt\">14\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-xml\" data-lang=\"xml\"><span class=\"line\"><span class=\"cl\"><span class=\"nt\">&lt;stackpanel.resources&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;controls:hierarchicaldatatemplate<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">x:key=<\/span><span class=\"s\">&#34;TaxonomyTemplate&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">itemssource=<\/span><span class=\"s\">&#34;{Binding Subclasses}&#34;<\/span><span class=\"nt\">&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;stackpanel<\/span> <span class=\"na\">orientation=<\/span><span class=\"s\">&#34;Horizontal&#34;<\/span><span class=\"nt\">&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;contentpresenter<\/span> <span class=\"na\">margin=<\/span><span class=\"s\">&#34;0 0 4 0&#34;<\/span> <span class=\"na\">content=<\/span><span class=\"s\">&#34;???&#34;<\/span> <span class=\"nt\">\/&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;textblock<\/span> <span class=\"na\">text=<\/span><span class=\"s\">&#34;{Binding Classification}&#34;<\/span> <span class=\"nt\">\/&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;\/stackpanel&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;\/controls:hierarchicaldatatemplate&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nt\">&lt;\/stackpanel.resources&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nt\">&lt;controls:treeview<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">x:name=<\/span><span class=\"s\">&#34;MasterTree&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">itemtemplate=<\/span><span class=\"s\">&#34;{StaticResource TaxonomyTemplate}&#34;<\/span> <span class=\"nt\">\/&gt;<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><p>I&rsquo;ve added a ContentPresenter and the Content is what we&rsquo;re interested in setting dynamically.<\/p>\n<h2 id=\"option-1---the-fixed-template\">Option #1 - The Fixed Template<\/h2>\n<p>If you have a rigidly defined hierarchy where you know the exact icon you want at each level you&rsquo;re in luck, there is already a sample showing how to do just that in the NestedHierarchicalDataTemplate scenario, using three separate HierarchicalDataTemplates, one for each level. This has the advantage of being easy for your designers to style the icons independent of the code, the obvious downside is it&rsquo;s a fixed structure.<\/p>\n<h2 id=\"option-2---binding-to-a-property\">Option #2 - Binding to a Property<\/h2>\n<p>Another option is to add an Icon property to your object and bind the Content directly to it, like this:<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-xml\" data-lang=\"xml\"><span class=\"line\"><span class=\"cl\"><span class=\"nt\">&lt;contentpresenter<\/span> <span class=\"na\">margin=<\/span><span class=\"s\">&#34;0 0 4 0&#34;<\/span> <span class=\"na\">content=<\/span><span class=\"s\">&#34;{Binding Icon}&#34;<\/span> <span class=\"nt\">\/&gt;<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><p>In your descendent classes you can override the Icon property and return the appropriate image for that class. You can even go further and return different images based on state, such as availability, status, quantity, etc.<\/p>\n<p>Object model purists may be frothing at the mouth, since I dared put UI information into my objects, and in some scenarios I&rsquo;d completely agree but what we&rsquo;re doing here is creating UI model objects, not business model objects. It&rsquo;s a common pattern and has the great benefit of making your UI testable from inside unit tests instead of having to rely solely on UI macro recorder\/playback frameworks. I go so far as to recommend that if you&rsquo;re doing a lot with states like icons, if something checked, multi-selection, color-coding, etc. that you create objects that sit between your business object and the actual UI elements.<\/p>\n<p>Anytime you find yourself trying to get directly at a control to set\/check state ask yourself if there is something you could be binding to instead.<\/p>\n<h2 id=\"option-3---the-valueconverter\">Option #3 - The ValueConverter<\/h2>\n<p>If you&rsquo;re binding directly to business objects or really don&rsquo;t like the idea of adding an Icon property to your objects (you know who you are) then you can take all that logic and roll it up into a value converter. IValueConverters are these great things that convert between two different types of values (I know, shocking). A classic example is <a href=\"http:\/\/www.jeff.wilcox.name\/2008\/07\/13\/visibility-type-converter\/\">converting between a boolean and the Visibility enum<\/a>. We&rsquo;re going to apply the same concept but this time convert between a type (our business object) and an icon.<\/p>\n<p>First, we need a ValueConverter, what I&rsquo;m calling the IconConverter:<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\"> 1\n<\/span><span class=\"lnt\"> 2\n<\/span><span class=\"lnt\"> 3\n<\/span><span class=\"lnt\"> 4\n<\/span><span class=\"lnt\"> 5\n<\/span><span class=\"lnt\"> 6\n<\/span><span class=\"lnt\"> 7\n<\/span><span class=\"lnt\"> 8\n<\/span><span class=\"lnt\"> 9\n<\/span><span class=\"lnt\">10\n<\/span><span class=\"lnt\">11\n<\/span><span class=\"lnt\">12\n<\/span><span class=\"lnt\">13\n<\/span><span class=\"lnt\">14\n<\/span><span class=\"lnt\">15\n<\/span><span class=\"lnt\">16\n<\/span><span class=\"lnt\">17\n<\/span><span class=\"lnt\">18\n<\/span><span class=\"lnt\">19\n<\/span><span class=\"lnt\">20\n<\/span><span class=\"lnt\">21\n<\/span><span class=\"lnt\">22\n<\/span><span class=\"lnt\">23\n<\/span><span class=\"lnt\">24\n<\/span><span class=\"lnt\">25\n<\/span><span class=\"lnt\">26\n<\/span><span class=\"lnt\">27\n<\/span><span class=\"lnt\">28\n<\/span><span class=\"lnt\">29\n<\/span><span class=\"lnt\">30\n<\/span><span class=\"lnt\">31\n<\/span><span class=\"lnt\">32\n<\/span><span class=\"lnt\">33\n<\/span><span class=\"lnt\">34\n<\/span><span class=\"lnt\">35\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-csharp\" data-lang=\"csharp\"><span class=\"line\"><span class=\"cl\"><span class=\"kd\">public<\/span> <span class=\"k\">class<\/span> <span class=\"nc\">IconConverter<\/span> <span class=\"p\">:<\/span> <span class=\"n\">IValueConverter<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"kd\">public<\/span> <span class=\"kt\">object<\/span> <span class=\"n\">Convert<\/span><span class=\"p\">(<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"kt\">object<\/span> <span class=\"k\">value<\/span><span class=\"p\">,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">Type<\/span> <span class=\"n\">targetType<\/span><span class=\"p\">,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"kt\">object<\/span> <span class=\"n\">parameter<\/span><span class=\"p\">,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">CultureInfo<\/span> <span class=\"n\">culture<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"k\">value<\/span> <span class=\"k\">is<\/span> <span class=\"n\">Domain<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"c1\">\/\/ return icon for Domain<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"k\">value<\/span> <span class=\"k\">is<\/span> <span class=\"n\">Family<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"c1\">\/\/ return icon for Family<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"k\">value<\/span> <span class=\"k\">is<\/span> <span class=\"n\">Genus<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"c1\">\/\/ return icon for Genus<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">return<\/span> <span class=\"kc\">null<\/span><span class=\"p\">;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"kd\">public<\/span> <span class=\"kt\">object<\/span> <span class=\"n\">ConvertBack<\/span><span class=\"p\">(<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"kt\">object<\/span> <span class=\"k\">value<\/span><span class=\"p\">,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">Type<\/span> <span class=\"n\">targetType<\/span><span class=\"p\">,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"kt\">object<\/span> <span class=\"n\">parameter<\/span><span class=\"p\">,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">CultureInfo<\/span> <span class=\"n\">culture<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">throw<\/span> <span class=\"k\">new<\/span> <span class=\"n\">NotImplementedException<\/span><span class=\"p\">();<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><p>Next, add it as a resource in your application so you can use it in your XAML (you will probably also need to add your project&rsquo;s namespace to the XAML, that is where \u201clocal\u201d comes from in my sample):<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><span class=\"lnt\">2\n<\/span><span class=\"lnt\">3\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-xml\" data-lang=\"xml\"><span class=\"line\"><span class=\"cl\"><span class=\"nt\">&lt;usercontrol.resources&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;local:iconconverter<\/span> <span class=\"na\">x:key=<\/span><span class=\"s\">&#34;IconConverter&#34;<\/span> <span class=\"nt\">\/&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nt\">&lt;\/usercontrol.resources&gt;<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><p>Last, set the binding on the content presenter so it knows to use the converter when trying to determine the icon:<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\"> 1\n<\/span><span class=\"lnt\"> 2\n<\/span><span class=\"lnt\"> 3\n<\/span><span class=\"lnt\"> 4\n<\/span><span class=\"lnt\"> 5\n<\/span><span class=\"lnt\"> 6\n<\/span><span class=\"lnt\"> 7\n<\/span><span class=\"lnt\"> 8\n<\/span><span class=\"lnt\"> 9\n<\/span><span class=\"lnt\">10\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-xml\" data-lang=\"xml\"><span class=\"line\"><span class=\"cl\"><span class=\"nt\">&lt;controls:hierarchicaldatatemplate<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">x:key=<\/span><span class=\"s\">&#34;TaxonomyTemplate&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">itemssource=<\/span><span class=\"s\">&#34;{Binding Subclasses}&#34;<\/span><span class=\"nt\">&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;stackpanel<\/span> <span class=\"na\">orientation=<\/span><span class=\"s\">&#34;Horizontal&#34;<\/span><span class=\"nt\">&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;contentpresenter<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">margin=<\/span><span class=\"s\">&#34;0 0 4 0&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"na\">content=<\/span><span class=\"s\">&#34;{Binding Converter={StaticResource IconConverter}}&#34;<\/span> <span class=\"nt\">\/&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;textblock<\/span> <span class=\"na\">text=<\/span><span class=\"s\">&#34;{Binding Classification}&#34;<\/span> <span class=\"nt\">\/&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nt\">&lt;\/stackpanel&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nt\">&lt;\/controls:hierarchicaldatatemplate&gt;<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><p>This technique has the advantage of centralizing everything as well as being usable on any type of object you&rsquo;re using in your TreeView, whether they all descend from a common base-type or not and if you put it in the application&rsquo;s resources you can use it throughout your application. It is also still very testable from a unit test, which is always a plus.<\/p>\n<p>The downside is that the <strong>is<\/strong> operator is expensive in terms of performance so if you have a lot of different classes you&rsquo;re checking against, with a lot of items in the tree you may hit some perf issues. This can be mitigated by keying off of other data that may be unique to your class-hierarchy.<\/p>\n<h2 id=\"datatype\">DataType<\/h2>\n<p>The WPF crowd is probably jumping up and down saying, &ldquo;But wait, wait, what about DataTarget?!&rdquo; In WPF one way you&rsquo;d handle dynamic icons is to create a HierarchialDataTemplate per class you wanted to style and set its DataType property so when that Type appeared in the TreeView it would get its custom style. It works great and is a tasty way to handle these situations but alas it&rsquo;s not supported in Silverlight. Personally I actually prefer option #2 and #3 if all you&rsquo;re doing is changing icons.<\/p>\n<h2 id=\"limitless-options\">Limitless Options<\/h2>\n<p>For every option I&rsquo;ve proposed here there are probably a dozen others based on your specific needs, business objects and user interface. If you come up with a great solution or have a situation that you don&rsquo;t feel is covered here then please either leave a comment or visit us in the <a href=\"http:\/\/silverlight.net\/forums\/35.aspx\">forums<\/a>.<\/p>","category":{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/categories\/silverlight\/","term":"Silverlight","label":"Silverlight"}}},{"title":"The Silverlight Toolkit and You","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/the-silverlight-toolkit-and-you\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/the-silverlight-toolkit-and-you\/","updated":"2026-10-18T02:41:51+00:00","published":"2008-10-28T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"Ever since joining Microsoft back in August 2008 this blog has been pretty quiet and not just because I&rsquo;ve been rolling around in the autumn leaves on campus but because of this gem, the Silverlight Toolkit.\nAt its highest level the Silverlight Toolkit is a collection of great controls and utilities that are continually being improved and polished until they are of the highest and most useful caliber.","content":"<p>Ever since joining Microsoft back in August 2008 this blog has been pretty quiet and not just because I&rsquo;ve been rolling around in the autumn leaves on campus but because of this gem, the <a href=\"http:\/\/www.codeplex.com\/Silverlight\">Silverlight Toolkit<\/a>.<\/p>\n<p>At its highest level the Silverlight Toolkit is a collection of great controls and utilities that are continually being improved and polished until they are of the highest and most useful caliber. You can find all the great details about this release over on my <a href=\"http:\/\/blogs.msdn.com\/sburke\/archive\/2008\/10\/28\/silverlight-toolkit-now-available-for-download.aspx\">fearless leader&rsquo;s blog<\/a> and I highly recommend you check it out because beyond saying what the Silverlight Toolkit contains he also explains how it was built, how it will continue to be built and how it will be released in a very agile, very feedback-centric way.<\/p>\n<p>One thing I want to stress is how important you, the developers, designers and those of uncertain vocation, are to this process. Saying your feedback is valuable isn&rsquo;t just lip service; we are watching the <a href=\"http:\/\/www.codeplex.com\/Silverlight\/WorkItem\/List.aspx\">Issue Tracker<\/a>, we are reading <strong>and responding<\/strong> in the <a href=\"http:\/\/silverlight.net\/forums\/35.aspx\">Silverlight Controls forum<\/a>, we are reading blog comments, in short we are listening to the people who use these controls day in and day out.<\/p>\n<p>One of the features I love most about the Silverlight Toolkit is its iterative nature: We look at feedback, rub our brain cells together, roll up our sleeves and six to eight weeks later we have new controls that are ready to be previewed by the community or existing ones that have been polished to a high sheen by your feedback and <a href=\"http:\/\/code.msdn.microsoft.com\/silverlightut\/\">continued testing<\/a>.<\/p>\n<p>I&rsquo;m really looking forward to seeing what people do with these controls as well as what feedback is out there. I&rsquo;ll see everyone in <a href=\"http:\/\/silverlight.net\/forums\/35.aspx\">the forums<\/a> \ud83d\ude00<\/p>","category":{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/categories\/silverlight\/","term":"Silverlight","label":"Silverlight"}}},{"title":"Seattle - The First Weekend","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/seattle-the-first-weekend\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/seattle-the-first-weekend\/","updated":"2026-10-18T02:41:51+00:00","published":"2008-08-11T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"My first weekend living in Seattle is drawing to a close and as the sun very, very slowly sets I figured I&rsquo;d give a wee status report.\nRight now I&rsquo;m living in an apartment provided so nicely by Microsoft in an area of downtown Seattle called Belltown in a place The Shelby.","content":"<p>My first weekend living in Seattle is drawing to a close and as the sun very, very slowly sets I figured I&rsquo;d give a wee status report.<\/p>\n<p>Right now I&rsquo;m living in an apartment provided so nicely by Microsoft in an area of downtown Seattle called Belltown in a place <a href=\"http:\/\/maps.google.com\/maps?f=q&amp;hl=en&amp;geocode=&amp;q=2201+4th+Ave,+Seattle,+WA+98121&amp;sll=37.0625,-95.677068&amp;sspn=42.766543,58.447266&amp;ie=UTF8&amp;ll=47.614828,-122.34302&amp;spn=0.008925,0.014269&amp;z=16&amp;iwloc=addr\">The Shelby<\/a>. It&rsquo;s a fairly modern, clean, <a href=\"http:\/\/theshelby.com\/melrose.html\">1 bedroom place<\/a> with a kitchen and dinning nook that fits two people rather well. Fully furnished though someone should talk to whomever outfitted this place, we need more towel racks, seriously people. Towel racks.<\/p>\n<p>The area is pretty much full of hipster kids, upscale restaurants, hidden gems, halfway houses and the fire station. Lot&rsquo;s of scooters go zipping around the place as well so scooter mania has hit here hard as well. I can walk five blocks into the heart of downtown, six blocks and I&rsquo;m in the famous Pike&rsquo;s Market, three blocks to a killer Mediterranean restaurant, eight blocks to the Puget Sound waterfront and most importantly one block to my new favorite watering hole, Two Bells. From the front door I can see the Space Needle just a few blocks away.<\/p>\n<p>First, the food. The food here is amazing, we have yet to eat at a bad place in downtown Seattle. First day lunch was at the <a href=\"http:\/\/www.zeitooncafe.com\/\">Zeitoon Cafe<\/a> where I had a killer panini, dinner at a great sushi place that had items I&rsquo;ve never seen before plus three Japanese business men were dinning which is always a good sign. Next night was pizza at <a href=\"http:\/\/www.tomdouglas.com\/serious\/index.html\">Serious Pie<\/a>, a small, quaint upscale pizzeria where everyone sits at shared tables while enjoying entirely unique appetizers and pizzas. A warning though for my purist friends (Jeremy, I&rsquo;m looking at you) there is no classic New York or Chicago style pizza on the menu so I&rsquo;m still on a quest for the best New York slice in Seattle. Tonight&rsquo;s dinner was at Two Bells, a bar &amp; grill that captured my heart and stomach. Low-key, no pretension bar &amp; grill with killer hamburgers, Guinness on tap and a great mix of people from tattoo&rsquo;d lasses to couples in Dockers. It&rsquo;s only a block away from The Shelby and has a high probability of becoming my favorite local watering hole. Kevin, Billy, Ben, Sean, this is where we&rsquo;d meet for a pint after work. I wish like hell we could.<\/p>\n<p>The weather has been great, only the smallest amount of rain, comfortable temps and sunshine. In fact the first day here I was missing our nice AC unit back in Colorado. Even downtown there are trees everywhere and when walking by Bell &amp; 4th (one block over) you can look right down to the Sound, or turn your head a bit and on a clear day make out the mountains. All in all it&rsquo;s a beautiful city and I can see why so many people love it. I&rsquo;ll report back tomorrow about the traffic though, I&rsquo;m sure all these people equals one huge traffic problem of evil.<\/p>\n<p>In fact I&rsquo;m surprised there is no cohesive public transportation. There are a half dozen small networks but nothing like the London Underground or D.C. subway system. A nice gentleman on the plane who bought be my Jack &amp; Ginger attributed this to all the tree huggers who quite literally can&rsquo;t bare to part with a single tree to make way for unified light rail or subway system. It&rsquo;s the classic curse of the West, since it was developed so much later than the East more people could afford personal transport and so the need was never as great. Plus the West wasn&rsquo;t exactly settled by socialites and debutantes so finding a nice communal way for everyone to get around probably wasn&rsquo;t on the top of any of these anti-social explorer&rsquo;s lists.<\/p>\n<p>This is my first time as a true Urbanite, living downtown, walking to the local market (Ralph&rsquo;s), being able to stumble home from the bar (Two Bells), walking to the bus for work (The 545 Express), hitting up the clubs (I hear them at night so I know they&rsquo;re around) and generally enjoying not having to fire up the car or spend money on gas to get to 90% of what I need to. I&rsquo;m sure once the constant rain and snow hits I won&rsquo;t be whistling such a merry little tune but I&rsquo;ll let the city court me a little while longer.<\/p>\n<p>It still feels surreal, like I&rsquo;m on some huge extended vacation and that I&rsquo;m just staying in a suite at some hotel for awhile but I have a feeling after tomorrow that illusion will come crashing down. A few days of work I&rsquo;m sure will bring me right back down to Earth :)<\/p>"},{"title":"Full Disclosure","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/full-disclosure\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/full-disclosure\/","updated":"2026-10-18T02:41:51+00:00","published":"2008-08-08T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"It&rsquo;s all about the snappy opening line, watch any classic movie from the 40&rsquo;s and you&rsquo;ll realize the importance of the opening line. If you need some evidence check out &lsquo;His Girl Friday&rsquo;, at least the first 20 minutes, for some of what I consider some of the back &amp; forth dialog around.","content":"<p>It&rsquo;s all about the snappy opening line, watch any classic movie from the 40&rsquo;s and you&rsquo;ll realize the importance of the opening line. If you need some evidence check out &lsquo;<a href=\"http:\/\/www.imdb.com\/title\/tt0032599\/\">His Girl Friday<\/a>&rsquo;, at least the first 20 minutes, for some of what I consider some of the back &amp; forth dialog around. Of course the classic for lines from the 40&rsquo;s is arguably &lsquo;<a href=\"http:\/\/www.imdb.com\/title\/tt0034583\/\">Casablanca<\/a>&rsquo; and if you&rsquo;ve never seen it you owe it to yourself to watch it with a bottle and some friends, you&rsquo;ll be amazed at how many lines come from just that one movie.<\/p>\n<p>The point, if I must make one, is that I&rsquo;ve been trying to figure out a snappy black and white, soft focus opening line that says, &ldquo;Well kids, seems the Universe has called my bluff and it&rsquo;s time to put my money where my mouth is when it comes to Microsoft.&rdquo; Starting August 11th, 2008 I&rsquo;ll be an official Microsoft employee working as a program manager on the <a href=\"http:\/\/silverlight.net\/default.aspx\">Silverlight<\/a> team in Seattle, WA.<\/p>\n<p>I&rsquo;m not sure exactly what that means except that I hear rumors from my new boss <a href=\"http:\/\/blogs.msdn.com\/sburke\/\">Shawn Burke<\/a> that it&rsquo;s something to do with controls and being open and agile and designing these fancy little usability bundles of love. Even though my title says &ldquo;Program Manager&rdquo; I have a feeling I&rsquo;m still going to be very code heavy, since code is and always will be my #1 passion and I&rsquo;ll do everything I can to make sure I&rsquo;m still slinging lines of code on a daily basis like a monkey flings poo. They probably won&rsquo;t be the production lines of code but that&rsquo;s OK, I can finally admit that while I think my coding kung fu is deadly I have this odd tendency to drop a project once I figure out the core problem. After that it&rsquo;s just typing and I get a much bigger thrill out of problem solving than solution implementing.<\/p>\n<p>Oddly enough the whole Silverlight mumbo-jumbo isn&rsquo;t what I want to talk about (though I&rsquo;m sure I will soon enough), it&rsquo;s the uprooting of my life from Denver, CO to Seattle, WA. It&rsquo;s leaving a job I worked at for 14 years, where I had a team of friends that were more like brothers that oddly enough gave me free rein to try out any crazy design idea that popped into my head. It&rsquo;s leaving friends that I could count on for anything from making me iced coffee to helping me tow a clutchless car home from <a href=\"http:\/\/maps.live.com\/?q=lusk%2c+wy&amp;mkt=en-US&amp;FORM=BYRE\">Lusk, Wyoming<\/a> and everything in between. A huge family, aye, more a clan, that made every family gathering something to be looked forward to rather than dreaded, with everything from some of the best food you&rsquo;ve ever tasted to <a href=\"http:\/\/www.flickr.com\/photos\/oster\/183137901\/\">Irish<\/a> <a href=\"http:\/\/www.flickr.com\/photos\/oster\/25984152\/\">step-dancing<\/a> to <a href=\"http:\/\/www.papajuke.com\/\">smoking Blues<\/a> to ballet to a nephew that&rsquo;s obsessed with any kind of construction equipment, preferably in &lsquo;Tear Shit Up&rsquo; yellow. To all those still in Denver I love you, dearly and deeply.<\/p>\n<p>I will miss Denver, the people, friends, family, the exploding cultural scene, the moments that can&rsquo;t be captured over XBox Live, and yet I&rsquo;m also excited to be in Seattle, at Microsoft, trying something new, creating new stories, meeting new people, finding new dive bars, playing host to all my visiting friends and family, bringing whatever it is I am to Microsoft (which is usually only bad singing and a love of strong drink) and generally starting a new chapter in my life.<\/p>\n<p>Today is my first day in Seattle, let the adventure begin!<\/p>"},{"title":"ZuneKeys Updated for Zune 2.5","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/zunekeys-updated-for-zune-2-5\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/zunekeys-updated-for-zune-2-5\/","updated":"2026-10-18T02:41:51+00:00","published":"2008-05-08T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"Another new Zune client update, another ZuneKeys. For those that don&rsquo;t know ZuneKeys gives you a few hotkeys to control playing and pausing the Zune software from any application (hence why they&rsquo;re called global hotkeys). I stole the idea from WinAmp because I&rsquo;m always needing to pause or skip tracks and it&rsquo;s much easier to do it with a quick Ctrl + Alt + Home rather than opening up the software and finding the pause button.","content":"<p>Another new Zune client update, another <a href=\"https:\/\/whiskeyandcode.com\/zunekeys-global-hotkey-support-for-zune\">ZuneKeys<\/a>. For those that don&rsquo;t know ZuneKeys gives you a few hotkeys to control playing and pausing the Zune software from any application (hence why they&rsquo;re called global hotkeys). I stole the idea from WinAmp because I&rsquo;m always needing to pause or skip tracks and it&rsquo;s much easier to do it with a quick Ctrl + Alt + Home rather than opening up the software and finding the pause button.<\/p>\n<p>It&rsquo;s a super-tiny 31k app. Just unzip and run and it sits in your tray listening for a hotkey. Uou can play, pause, stop, skip tracks or adjust the volume. If anyone on the Zune team reads this I&rsquo;d love to know if there are any official messages I can send to the application for control because right now I&rsquo;m faking it by sending the same messages those fancy (and bulky) multimedia keyboards send.<\/p>\n<p><a href=\"https:\/\/whiskeyandcode.com\/downloads\/ZuneKeys.zip\">Download ZuneKeys<\/a><\/p>","category":{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/categories\/zune\/","term":"Zune","label":"Zune"}}},{"title":"Springloops for Web Site Deployment","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/springloops-for-web-site-deployment\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/springloops-for-web-site-deployment\/","updated":"2026-10-18T02:41:51+00:00","published":"2008-04-24T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"One of my clients recently switched hosting providers which threw me for a loop because I was doing all their web site deployment using Subversion. I&rsquo;d make a change on my development box, commit it, ssh over to their host and issue a matching svn update.","content":"<p>One of my clients recently switched hosting providers which threw me for a loop because I was doing all their web site deployment using Subversion. I&rsquo;d make a change on my development box, commit it, ssh over to their host and issue a matching svn update. It worked great and gave me a big warm fuzzy.<\/p>\n<p>The new host sadly doesn&rsquo;t have svn installed and while I could probably bug them to install it for me I thought I&rsquo;d see what others out there were doing when it came to shared hosting. Seems svn+rsync is a popular choice along with variations on that theme but I wanted something simpler. Enter Springloops.<\/p>\n<p><a href=\"http:\/\/springloops.com\/\">Springloops<\/a> is basically a hosted svn repository that will push your changes via FTP to a deployment server, but that doesn&rsquo;t truly convey just how smooth an experience it really is. Getting set up is a snap, the interface is well thought out and has a great aesthetic. You know there is a svn repository behind the interface but it&rsquo;s presented in a very non-threatening for the non-nerd way.<\/p>\n<p>Once you&rsquo;ve imported all your files, using whatever svn client you like, you setup a deployment server, giving it your FTP host, path and log in information and from that point on deployment is as simple as a button click. All of this for free and if you step up to one of their paid plans you get automatic deployment, large storage, more deployment servers and more depending on the level you pick.<\/p>\n<p>All in all I actually like this solution better than what I had before because it&rsquo;s easier for others to interact with your site as well as push deployments. Anyone looking for a way to use version control (you are using version control, right?) with shared hosting should definitely give Springloops a try.<\/p>"},{"title":"Migrations In SubSonic","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/migrations-in-subsonic\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/migrations-in-subsonic\/","updated":"2026-10-18T02:41:51+00:00","published":"2008-04-13T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"A few weeks ago Rob Conery foolishly tapped me to help get migrations in SubSonic up to snuff and I&rsquo;ve been working on them ever since trying to sneak them into the latest SubSonic beta. I&rsquo;ve changed the way they&rsquo;re implemented slightly from when Rob first talked about them so here&rsquo;s a quick re-introduction to migrations.","content":"<p>A few weeks ago <a href=\"http:\/\/blog.wekeroad.com\/\">Rob Conery<\/a> foolishly tapped me to help get migrations in SubSonic up to snuff and I&rsquo;ve been working on them ever since trying to sneak them into the latest <a href=\"http:\/\/blog.wekeroad.com\/blog\/subsonic-2-1-beta-3-is-ready\/\">SubSonic beta<\/a>. I&rsquo;ve changed the way they&rsquo;re implemented slightly from when Rob first talked about them so here&rsquo;s a quick re-introduction to migrations.<\/p>\n<p>Migrations are a way to create and version your database schema using code rather than having to rely on SQL scripts or compare and sync tools. They allow you to quickly rollback schema changes as well migrate schema changes from your development database to staging and then on to production. In a nutshell they rock when it comes to database maintenance, versioning and deployment.<\/p>\n<h2 id=\"migration-breakdown\">Migration Breakdown<\/h2>\n<p>A migration is a class that descends from SubSonic.Migration and overrides both the Up() and Down() methods. Up() is used when going up a version and Down() is used to restore the database schema to the pre-Up() state. Anything you do in the Up() should be undone in your Down().<\/p>\n<p>By convention they are put in a Migrations folder off the root of your project folder. While the actual name of the class isn&rsquo;t important the name of the file is critical because this is how SubSonic determines which version the migration represents. The naming convention is <code>000_MigrationName.cs<\/code> (or .vb) with the version number represented by leading three numerics, starting at &lsquo;001&rsquo; and working your way up. Currently it&rsquo;s pretty particular about that naming convention so make sure it&rsquo;s exactly three numerics, padded with zeros if needed. It&rsquo;s convention to name your migration file something descriptive and to also not repeat names, such as:<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-bash\" data-lang=\"bash\"><span class=\"line\"><span class=\"cl\">001_AddExerciseTable.cs\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><h2 id=\"an-example\">An Example<\/h2>\n<p>Let&rsquo;s start with a simple example and break it down:<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\"> 1\n<\/span><span class=\"lnt\"> 2\n<\/span><span class=\"lnt\"> 3\n<\/span><span class=\"lnt\"> 4\n<\/span><span class=\"lnt\"> 5\n<\/span><span class=\"lnt\"> 6\n<\/span><span class=\"lnt\"> 7\n<\/span><span class=\"lnt\"> 8\n<\/span><span class=\"lnt\"> 9\n<\/span><span class=\"lnt\">10\n<\/span><span class=\"lnt\">11\n<\/span><span class=\"lnt\">12\n<\/span><span class=\"lnt\">13\n<\/span><span class=\"lnt\">14\n<\/span><span class=\"lnt\">15\n<\/span><span class=\"lnt\">16\n<\/span><span class=\"lnt\">17\n<\/span><span class=\"lnt\">18\n<\/span><span class=\"lnt\">19\n<\/span><span class=\"lnt\">20\n<\/span><span class=\"lnt\">21\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-csharp\" data-lang=\"csharp\"><span class=\"line\"><span class=\"cl\"><span class=\"k\">using<\/span> <span class=\"nn\">System<\/span><span class=\"p\">;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"k\">using<\/span> <span class=\"nn\">System.Collections.Generic<\/span><span class=\"p\">;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"k\">using<\/span> <span class=\"nn\">System.Text<\/span><span class=\"p\">;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"k\">using<\/span> <span class=\"nn\">SubSonic<\/span><span class=\"p\">;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"k\">namespace<\/span> <span class=\"nn\">SubSonic<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"kd\">public<\/span> <span class=\"k\">class<\/span> <span class=\"nc\">Migration001<\/span><span class=\"p\">:<\/span><span class=\"n\">Migration<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"kd\">public<\/span> <span class=\"kd\">override<\/span> <span class=\"k\">void<\/span> <span class=\"n\">Up<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">TableSchema<\/span><span class=\"p\">.<\/span><span class=\"n\">Table<\/span> <span class=\"n\">t<\/span> <span class=\"p\">=<\/span> <span class=\"n\">CreateTable<\/span><span class=\"p\">(<\/span><span class=\"s\">&#34;Flights&#34;<\/span><span class=\"p\">);<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">t<\/span><span class=\"p\">.<\/span><span class=\"n\">AddColumn<\/span><span class=\"p\">(<\/span><span class=\"s\">&#34;Name&#34;<\/span><span class=\"p\">,<\/span> <span class=\"n\">System<\/span><span class=\"p\">.<\/span><span class=\"n\">Data<\/span><span class=\"p\">.<\/span><span class=\"n\">DbType<\/span><span class=\"p\">.<\/span><span class=\"n\">String<\/span><span class=\"p\">);<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">t<\/span><span class=\"p\">.<\/span><span class=\"n\">AddColumn<\/span><span class=\"p\">(<\/span><span class=\"s\">&#34;FlightNumber&#34;<\/span><span class=\"p\">,<\/span> <span class=\"n\">System<\/span><span class=\"p\">.<\/span><span class=\"n\">Data<\/span><span class=\"p\">.<\/span><span class=\"n\">DbType<\/span><span class=\"p\">.<\/span><span class=\"n\">String<\/span><span class=\"p\">,<\/span> <span class=\"m\">100<\/span><span class=\"p\">);<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">t<\/span><span class=\"p\">.<\/span><span class=\"n\">AddColumn<\/span><span class=\"p\">(<\/span><span class=\"s\">&#34;DateTraveling&#34;<\/span><span class=\"p\">,<\/span> <span class=\"n\">System<\/span><span class=\"p\">.<\/span><span class=\"n\">Data<\/span><span class=\"p\">.<\/span><span class=\"n\">DbType<\/span><span class=\"p\">.<\/span><span class=\"n\">DateTime<\/span><span class=\"p\">,<\/span> <span class=\"m\">0<\/span><span class=\"p\">,<\/span> <span class=\"kc\">false<\/span><span class=\"p\">,<\/span> <span class=\"s\">&#34;getdate()&#34;<\/span><span class=\"p\">);<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">AddSubSonicStateColumns<\/span><span class=\"p\">(<\/span><span class=\"n\">t<\/span><span class=\"p\">);<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"kd\">public<\/span> <span class=\"kd\">override<\/span> <span class=\"k\">void<\/span> <span class=\"n\">Down<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">DropTable<\/span><span class=\"p\">(<\/span><span class=\"s\">&#34;Flights&#34;<\/span><span class=\"p\">);<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><p>In the example the &lsquo;Flights&rsquo; table is created, then three columns are added to it, followed by the standard SubSonic state columns. If you don&rsquo;t specify a primary key one will be created for you with the pattern of &lsquo;TableNameID&rsquo;, so that&rsquo;s one less thing to worry about. The Down() method undoes everything we did in the Up() by dropping the &lsquo;Flights&rsquo; table.<\/p>\n<h2 id=\"available-methods\">Available Methods<\/h2>\n<p>Currently the methods available from inside your migration are:<\/p>\n<ul>\n<li><code>CreateTable(string tableName)<\/code> - This creates and returns a table schema to which you can add your columns, as seen in the example.<\/li>\n<li><code>DropTable(string tableName)<\/code> - Does exactly what it says. If your Up() has a CreateTable() you&rsquo;ll need a corresponding DropTable().<\/li>\n<li><code>AddColumn(string tableName, string columnName, ...)<\/code> - Used to add a new column to an existing table. It has all the same overloads as TableSchema.Table.AddColumn() except the first parameter is the name of the table you&rsquo;ll be adding columns to.<\/li>\n<li><code>RemoveColumn(string tableName, string columnName)<\/code> - You only get one guess that this does :)<\/li>\n<li><code>AlterColumn(string tableName, string columnName, ...)<\/code> - Used to alter an existing column, again, the same overloads as AddColumn.<\/li>\n<li><code>AddSubSonicStateColumns(TableSchema.Table table)<\/code> - Adds the conventional SubSonic state columns to your table. I&rsquo;ll be adding another overload that just takes a tableName if you want to add those columns to an existing table.<\/li>\n<\/ul>\n<h2 id=\"running-your-migrations\">Running your Migrations<\/h2>\n<p>To run your migrations you&rsquo;ll use SubCommander, the same tool used to generate your models but with the &lsquo;migrate&rsquo; command. The simplest usage is:<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-powershell\" data-lang=\"powershell\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">sonic<\/span> <span class=\"n\">migrate<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><p>That&rsquo;s it. It&rsquo;ll use your default provider, look for your migrations in Migrations and run every migration Up() starting at your database&rsquo;s current migration up the last one found in the Migrations folder. You can also specify the provider, migration directory and version at the command line like this:<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-powershell\" data-lang=\"powershell\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">sonic<\/span> <span class=\"n\">migrate<\/span> <span class=\"p\">\/<\/span><span class=\"n\">provider<\/span> <span class=\"s2\">&#34;Northwind&#34;<\/span> <span class=\"p\">\/<\/span><span class=\"n\">migrationDirectory<\/span> <span class=\"s2\">&#34;D:TestingMigrations&#34;<\/span> <span class=\"p\">\/<\/span><span class=\"n\">version<\/span> <span class=\"mf\">4<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><p>A few things to remember:<\/p>\n<ul>\n<li>Migrations by convention are looked for in a Migrations folder off the root of your project, though this can be changed via the command line. (\/migrationDirectory &ldquo;D:Migrations&rdquo;)<\/li>\n<li>You run a migration against a single provider at a time, there is no support for specifying the provider inside the migration. The main reason is portability, often you&rsquo;ll be running this migrations against different databases and hardcoding the provider name in the migration destroys their usefulness.<\/li>\n<li>Migrations will run against the default provider unless otherwise specified via the command line (\/provider &ldquo;Northwind&rdquo;)<\/li>\n<li>By default migrations will try to go up to the latest version found in the migrations folder. To go up or down to a specific version use \/version X to indicate which version.<\/li>\n<li>To enable migration support a new table &lsquo;SubSonicSchemaInfo&rsquo; will be created in your database, so don&rsquo;t delete it and tell your DBA that it&rsquo;s OK :)<\/li>\n<\/ul>\n<h3 id=\"todo\">TODO<\/h3>\n<p>These are things you <em>should<\/em> see before the next beta drop, but don&rsquo;t hold me to it :)<\/p>\n<ul>\n<li>Ability to generate your migration code skeleton using sonic.exe.<\/li>\n<li>Add RenameTable()<\/li>\n<li>Add RenameColumn()<\/li>\n<li>Add ability to execute ad-hoc sql, for creating stored procs, views, creating roles, users, etc.<\/li>\n<li>Add constraints<\/li>\n<li>Add foreign keys<\/li>\n<\/ul>","category":{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/categories\/subsonic\/","term":"SubSonic","label":"SubSonic"}}},{"title":"So You Want To Be a Web Developer","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/so-you-want-to-be-a-web-developer\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/so-you-want-to-be-a-web-developer\/","updated":"2026-10-18T02:41:51+00:00","published":"2008-04-03T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"I just had a friend at work ask that most innocuous of questions, &ldquo;So, what should I learn if I want to be web developer?&rdquo; which led us into a pretty good discussion about all things web related and to give him (Hi Nat!","content":"<p>I just had a friend at work ask that most innocuous of questions, &ldquo;So, what should I learn if I want to be web developer?&rdquo; which led us into a pretty good discussion about all things web related and to give him (Hi Nat!) a place to reference my ramblings I thought I&rsquo;d jot down what I suggested.<\/p>\n<h2 id=\"define-web-developer\">Define &ldquo;Web Developer&rdquo;<\/h2>\n<p>Web developer can pretty much mean anything these days so I find it best to ask yourself what it is you really want to do. I&rsquo;ve been in shops where web developer meant just HTML\/CSS while in others the dev does it all, from comps to HTML to database interaction. In my friend&rsquo;s case it meant creating a dynamic database-driven website from nothing more than a designer&rsquo;s comps and the napkin the business leaders scribbled on in between rounds of golf. Which was good because that&rsquo;s how I define it.<\/p>\n<h2 id=\"learn-htmlcss\">Learn HTML\/CSS<\/h2>\n<p>You&rsquo;ve gotta learn the basic currency of the web before you can get fancy pants on it so getting a solid understanding of good, standards-based semantic HTML and CSS (vs. table tag soup) is key. Regardless of which whiz-bang rocket framework you use in the end it all comes down to pushing HTML so you need to know how to craft good basic pages.<\/p>\n<p>I also suggest forgetting about Dreamweaver, FrontPage or any other HTML editor, for now. In fact I&rsquo;d suggest using just a really solid text editor like <a href=\"http:\/\/www.textpad.com\/\">TextPad<\/a>, <a href=\"http:\/\/intype.info\/home\/index.php\">InType<\/a> or <a href=\"http:\/\/www.e-texteditor.com\/\">E<\/a>. My current favorite is InType because it doesn&rsquo;t require the cygwin install like E yet it has better syntax highlighting and snippet expansion than TextPad. When learning HTML you want to be as close to the metal as possible.<\/p>\n<p>There are a ton of great books and websites out there teaching this stuff. Two of my favorites are <a href=\"http:\/\/www.simplebits.com\/publications\/bulletproof\/\">&ldquo;Bulletproof Web Design&rdquo;<\/a> and <a href=\"https:\/\/whiskeyandcode.com\/blog\/admin\/Pages\/Web%20Standards%20Solutions\">&ldquo;Web Standards Solutions&rdquo;<\/a>, both by <a href=\"http:\/\/www.simplebits.com\/\">Dan Cederholm<\/a>, who presents web design (as in the HTML, not Photoshop comp work) in a real-world, useful manner. Good stuff.<\/p>\n<h2 id=\"learn-javascript\">Learn JavaScript<\/h2>\n<p>I&rsquo;m still iffy on this one since you could argue that JavaScript could come later but I feel it&rsquo;s best to at least get a rudimentary understanding of JavaScript to learn the basics like client-side validation, confirmation boxes and how to use one of the various JavaScript libraries out there like <a href=\"http:\/\/www.prototypejs.org\/\">Prototype<\/a>, <a href=\"http:\/\/jquery.com\/\">jQuery<\/a>, <a href=\"http:\/\/extjs.com\/\">ExtJS<\/a>. Most server-side frameworks try to color the basic way you use JavaScript which I feel can dilute a person&rsquo;s understanding of just what client-side coding is all about.<\/p>\n<h2 id=\"pick-your-poison-server-side-framework\">Pick Your Poison (Server-Side Framework)<\/h2>\n<p>Ahh, the golden ring, the big prize, what it&rsquo;s all about, at least for me, the server-side framework that makes all the magic happen when it comes to dynamic page generation. This was probably the hardest thing to guide him on because I&rsquo;ve worked with most of the major frameworks and they all have pros and cons. The big three to me are <a href=\"http:\/\/asp.net\/\">ASP.NET<\/a>, <a href=\"http:\/\/www.rubyonrails.org\/\">Rails<\/a> and <a href=\"http:\/\/www.php.net\/\">PHP<\/a>. They all have great support, vibrant communities and very active development. There is also Java, but I was badly scarred when I learned Java&rsquo;s AWT and Swing frameworks so I&rsquo;m going to completely ignore it since even thinking about it again makes me whimper :)<\/p>\n<h3 id=\"aspnethttpaspnet\"><a href=\"http:\/\/asp.net\/\">ASP.NET<\/a><\/h3>\n<p>I&rsquo;m a little biased towards .NET because it offers a great springboard in terms further types of development. Want to do create a desktop application? No problem, you already know the IDE and C# (OK, or Visual Basic). Feel like being more creative and want to do something Flashy? .NET has you covered with <a href=\"http:\/\/silverlight.net\/\">Silverlight<\/a>. It&rsquo;s like a gateway drug of development, especially once you start factoring in things like <a href=\"http:\/\/www.codeplex.com\/Wiki\/View.aspx?ProjectName=IronPython\">IronPython<\/a>, <a href=\"http:\/\/www.ironruby.net\/\">IronRuby<\/a> and <a href=\"http:\/\/www.asp.net\/mvc\/\">MVC<\/a>. And despite what some people say ASP.NET isn&rsquo;t just for corporate drones, there&rsquo;s no Web 2.0 site out there that can&rsquo;t be coded in .NET. Downsides are that it&rsquo;s a little more complex to get started and that it&rsquo;ll warp your fragile little mind when it comes to the bastard child that is WebForms.<\/p>\n<h3 id=\"railshttpwwwrubyonrailsorg\"><a href=\"http:\/\/www.rubyonrails.org\/\">Rails<\/a><\/h3>\n<p>I think learning <a href=\"http:\/\/www.ruby-lang.org\/en\/\">Ruby<\/a> (the language of Rails) is a great addition to any developer&rsquo;s knowledge, regardless of what they code in by day. If someone is interested strictly in single focus, highly dynamic web sites and really has an aversion to Microsoft this is where I&rsquo;d steer them. It&rsquo;s a much better abstraction of the web than .NET&rsquo;s WebForms and you can really get rocking quickly without having to understand much with Rails. The downside is finding jobs in your area looking for entry-level Rails devs.<\/p>\n<h3 id=\"phphttpwwwphpnet\"><a href=\"http:\/\/www.php.net\/\">PHP<\/a><\/h3>\n<p>This is sort of the monkey in the middle. There are a ton of great PHP jobs but it&rsquo;s lost a little of it&rsquo;s hipster sizzle, which isn&rsquo;t exactly a bad thing. PHP is a great choice for the newbie consultant looking to work with small to medium-sized companies because there are a lot of CMS packages in PHP and you can get solid PHP hosting for a song.<\/p>\n<h2 id=\"summary\">Summary<\/h2>\n<p>In the end I suggested that he go through job descriptions he was interested in (shhh, don&rsquo;t tell his boss) and see what they were asking for in terms of knowledge. This brings up another good point, why do you want to be a web developer? If it&rsquo;s just for a better job then I stand by my suggestion. On the other hand if it&rsquo;s because you want to do Website X or Project Y then that completely changes the game and makes it easier. You pick the technology and learning curve that will get you quickest to your goal. In the end users could care less if your site is in Rails, .NET or PHP.<\/p>"},{"title":"What ASP.NET MVC Can Learn About REST from Rails","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/what-asp-net-mvc-can-learn-about-rest-from-rails\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/what-asp-net-mvc-can-learn-about-rest-from-rails\/","updated":"2026-10-18T02:41:51+00:00","published":"2008-02-20T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"I&rsquo;m starting to see more ASP.NET MVC samples and questions come out and I&rsquo;m realizing that a large portion of the ASP.NET crowd doesn&rsquo;t even realize that a huge reason for the MVC movement is because of the Ruby on Rails framework. A lot of new .","content":"<p>I&rsquo;m starting to see more ASP.NET MVC samples and questions come out and I&rsquo;m realizing that a large portion of the ASP.NET crowd doesn&rsquo;t even realize that a huge reason for the MVC movement is because of the Ruby on Rails framework. A lot of new .NET MVC developers are struggling with architectural questions that have already been debated and answered in the Rails community, which makes Rails a great resource for when you&rsquo;re first starting out or you&rsquo;re curious how to handle certain situations, like nested resources or how to structure your controllers.<\/p>\n<p>Speaking of controllers one great thing from Rails that I hope more MVC developers embrace is REST. Instead of repeating everything just watch David Heinemeier Hansson&rsquo;s keynote speech from RailsConf back in 2006. Sure, it&rsquo;s almost two years but for ASP.NET developers it may as well be yesterday. I&rsquo;d suggest starting from the second part since the first segment is just normal conference ra-ra-ra.<\/p>\n<p><a href=\"http:\/\/www.scribemedia.org\/2006\/07\/09\/dhh\">Check it out here<\/a> (don&rsquo;t forget to download the slides that he refers to <a href=\"http:\/\/downloads.scribemedia.net\/rails2006\/worldofresources.pdf\">here<\/a>).<\/p>\n<h2 id=\"note\">Note<\/h2>\n<p>He talks about using a semi-colon in the URL to denote an aspect\/action of a controller, like this:<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"sr\">\/people\/<\/span><span class=\"mi\">1<\/span><span class=\"p\">;<\/span><span class=\"n\">edit<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><p>Well, you can ignore that and just assume he <em>really<\/em> meant to say:<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"sr\">\/people\/<\/span><span class=\"mi\">1<\/span><span class=\"o\">\/<\/span><span class=\"n\">edit<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><p>They dropped that semi-colon silliness in Rails 2.0 and it feels much cleaner.<\/p>"},{"title":"Nested Resources In ASP.NET MVC","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/nested-resources-in-asp-net-mvc\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/nested-resources-in-asp-net-mvc\/","updated":"2026-10-18T02:41:51+00:00","published":"2008-02-08T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"Often you&rsquo;ll need to represent some hierarchical or parent-child relationship in your application and one thing you&rsquo;ll struggle with is how to cleanly mesh both the parent and child controllers yet keep them nice and RESTful. The secret is in good routing.","content":"<p>Often you&rsquo;ll need to represent some hierarchical or parent-child relationship in your application and one thing you&rsquo;ll struggle with is how to cleanly mesh both the parent and child controllers yet keep them nice and RESTful. The secret is in good routing.<\/p>\n<h2 id=\"the-problem\">The problem<\/h2>\n<p>A popular example is tickets belonging to events (event as in Burning Man, not OnClick) and you want to get all the tickets for a certain event, as well as be able to work with just tickets or events. You want nice and pretty urls as well, so you&rsquo;re hoping for something like this:<\/p>\n<table>\n<thead>\n<tr>\n<th>route<\/th>\n<th>description<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>\/events\/1\/tickets<\/td>\n<td>all tickets for event 1<\/td>\n<\/tr>\n<tr>\n<td>\/events\/1\/tickets\/new<\/td>\n<td>add a new ticket for event 1<\/td>\n<\/tr>\n<tr>\n<td>\/tickets\/list<\/td>\n<td>all tickets for all events<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2 id=\"the-messy-way\">The Messy Way<\/h2>\n<p>My first idea was to add a Tickets action to my Events controller so I could call <code>EventsController.Tickets(int eventId)<\/code> but that didn&rsquo;t really help when I wanted to view all the tickets for all the events. Plus it broke the whole REST idea and that&rsquo;s bad for maintainability.<\/p>\n<p>My second idea was a butt-ugly url along the lines of <code>\/tickets\/list?event_id=1<\/code> but that just kicks the whole MVC, SEO-friendly url philosophy in the nuts. Repeatedly.<\/p>\n<h2 id=\"the-routes-way\">The Routes Way<\/h2>\n<p>A <strong>Big Thanks<\/strong> goes to Adam Wiggins whose <a href=\"http:\/\/adam.blog.heroku.com\/past\/2007\/12\/20\/nested_resources_in_rails_2\/\">post about nested resources<\/a> finally set off the lightbulb in my brain. Instead of trying to make my controllers do all the work why not take advantage of the actual mechanism that&rsquo;s there to handle these sorts of things and put it to use. That would be the routing mechanism that makes all your urls pretty and dictates which controller does what. Here is the way to keep your urls pretty and to have both a separate Events and Tickets controller yet still maintain the cool parent\/child relationship:<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><span class=\"lnt\">2\n<\/span><span class=\"lnt\">3\n<\/span><span class=\"lnt\">4\n<\/span><span class=\"lnt\">5\n<\/span><span class=\"lnt\">6\n<\/span><span class=\"lnt\">7\n<\/span><span class=\"lnt\">8\n<\/span><span class=\"lnt\">9\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-csharp\" data-lang=\"csharp\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">RouteTable<\/span><span class=\"p\">.<\/span><span class=\"n\">Routes<\/span><span class=\"p\">.<\/span><span class=\"n\">Add<\/span><span class=\"p\">(<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">new<\/span> <span class=\"n\">Route<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">Url<\/span> <span class=\"p\">=<\/span> <span class=\"s\">&#34;events\/[eventId]\/tickets\/[action]\/[id]&#34;<\/span><span class=\"p\">,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">Defaults<\/span> <span class=\"p\">=<\/span> <span class=\"k\">new<\/span> <span class=\"p\">{<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">controller<\/span> <span class=\"p\">=<\/span> <span class=\"s\">&#34;Tickets&#34;<\/span><span class=\"p\">,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">action<\/span> <span class=\"p\">=<\/span> <span class=\"s\">&#34;List&#34;<\/span><span class=\"p\">,<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">id<\/span> <span class=\"p\">=<\/span> <span class=\"p\">(<\/span><span class=\"kt\">string<\/span><span class=\"p\">)<\/span><span class=\"kc\">null<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">},<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">RouteHandler<\/span> <span class=\"p\">=<\/span> <span class=\"k\">typeof<\/span><span class=\"p\">(<\/span><span class=\"n\">MvcRouteHandler<\/span><span class=\"p\">)<\/span> <span class=\"p\">});<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><p>Once I discovered this I smacked myself on the forehead for not realizing just how simple this whole thing was.<\/p>","category":{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/categories\/asp.net\/","term":"ASP.NET","label":"ASP.NET"}}},{"title":"Getting SubSonic Setup in Visual Studio","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/getting-subsonic-setup-in-visual-studio\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/getting-subsonic-setup-in-visual-studio\/","updated":"2026-10-18T02:41:51+00:00","published":"2008-02-04T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"I&rsquo;m a big fan of SubSonic, a ORM\/DAL generator \/ utility belt of goodness. Like any tool there is a little configuration and setup you need to do to get everything rolling and while Rob Conery has some great podcasts on doing just this, sometimes you just need to remember that one little option vs.","content":"<p>I&rsquo;m a big fan of <a href=\"http:\/\/subsonicproject.com\/default.aspx\">SubSonic<\/a>, a ORM\/DAL generator \/ utility belt of goodness. Like any tool there is a little configuration and setup you need to do to get everything rolling and while Rob Conery <a href=\"http:\/\/subsonicproject.com\/view\/using-the-command-line-tool.aspx\">has some great podcasts<\/a> on doing just this, sometimes you just need to remember that one little option vs. wanting to watch a 10 minute podcast again, regardless of how melodic and sweet are the dulcet tones of Mr. Conery&rsquo;s voice.<\/p>\n<h2 id=\"1-downloadhttpsubsonicprojectcom-and-install-subsonic\">1. <a href=\"http:\/\/subsonicproject.com\/\">Download<\/a> and Install SubSonic<\/h2>\n<p>Seems simple but hey, some people need to be told everything :)<\/p>\n<h2 id=\"2-create-subsonic-dal-as-an-external-tool\">2. Create SubSonic DAL as an external tool<\/h2>\n<p>Even though SubSonic supports Rails-style auto-gen of your DAL via build providers I like putting my model\/DAL in a separate class library and sadly build providers don&rsquo;t play well with class libraries.<\/p>\n<p>Go to Tools &rsquo; Externals Tools&hellip; click &ldquo;Add&rdquo; and make it look like this:<\/p>\n<p><a href=\"https:\/\/whiskeyandcode.com\/images\/ExternalTools.png\"><img src=\"https:\/\/whiskeyandcode.com\/images\/ExternalTools_thumb.png\" alt=\"External Tools\"><\/a><\/p>\n<ul>\n<li>That command is your path to <strong>sonic.exe<\/strong><\/li>\n<li>If you&rsquo;re working with the MVC Toolkit (and why aren&rsquo;t you?) then change &ldquo;App_CodeGenerated&rdquo; to &ldquo;ModelsGenerated&rdquo;<\/li>\n<\/ul>\n<h2 id=\"3-create-subsonic-db-as-an-external-tool\">3. Create SubSonic DB as an external tool<\/h2>\n<p>SubSonic can also version and script your database, very useful for source control and distributing your application. Same as above but make it look like this:<\/p>\n<p><a href=\"https:\/\/whiskeyandcode.com\/images\/ExternalTools2.png\"><img src=\"https:\/\/whiskeyandcode.com\/images\/ExternalTools2_thumb.png\" alt=\"External Tools (2)\"><\/a><\/p>\n<h2 id=\"4-install-subsonic-schema\">4. Install SubSonic Schema<\/h2>\n<p>I dislike any warnings during a build and one you&rsquo;ll get with SubSonic is it not knowing about the SubSonic config sections. I did a <a href=\"https:\/\/whiskeyandcode.com\/about\/#search=SubSonic\">blog post on how to fix this<\/a> awhile back but I&rsquo;m repeating here for the lazy (like myself):<\/p>\n<ol>\n<li>\n<p>Download <a href=\"https:\/\/whiskeyandcode.com\/SubSonicSchema.xsd\">SubSonicSchema.xsd<\/a> (if you right-click to download make sure you save it with an xsd extension)<\/p>\n<\/li>\n<li>\n<p>Put it in C:Program FilesMicrosoft Visual Studio 8.0XmlSchemas (adjust accordingly for VS2008)<\/p>\n<\/li>\n<li>\n<p>Edit DotNetConfig.xsd in the same folder and add the following line:<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-xml\" data-lang=\"xml\"><span class=\"line\"><span class=\"cl\"><span class=\"nt\">&lt;xs:include<\/span> <span class=\"na\">schemalocation=<\/span><span class=\"s\">&#34;SubSonicSchema.xsd&#34;<\/span> <span class=\"nt\">\/&gt;<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><p>(I added it right underneath the <code>&lt;xs:schema&gt;<\/code> opening tag, seems to work. Also, if you&rsquo;re using <strong>Vista<\/strong> you&rsquo;ll need to edit <code>DotNetConfig.xsd<\/code> in an editor that was started with right-click, Admin, otherwise it&rsquo;ll write a copy of the xsd into the Virtual Store and your changes will never take effect. Trust me, I learned this the hard way.)<\/p>\n<\/li>\n<li>\n<p>Close Visual Studio if it&rsquo;s running, re-open, ta-da you now have IntelliSense as well as no more annoying <em>&ldquo;Could not find schema information for&hellip;&rdquo;<\/em> messages.<\/p>\n<\/li>\n<\/ol>\n<h2 id=\"5-install-subsonic-code-snippets\">5. Install SubSonic code snippets<\/h2>\n<p>You add various sections into your web.config to wire up the magic and nothing is more boring than typing the same poop over and over again. I created some snippets that provide the various bits that you can download here (actually not quite yet since the bits are at work and my VPN is broken right now).<\/p>\n<p>And Bob&rsquo;s your Uncle, you have all the boring schtuff out of the way and now you&rsquo;re ready to start genning ya some code. If you don&rsquo;t actually know how to start genning your code then I&rsquo;d suggest watching some of those screencasts I mentioned above.<\/p>"},{"title":".NET Framework Guts Exposed","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/net-framework-guts-exposed\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/net-framework-guts-exposed\/","updated":"2026-10-18T02:41:51+00:00","published":"2008-01-17T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"Remember that scene in Star Wars when Luke (or was it Han Solo?) cuts open that crazy goat-beast thing&rsquo;s belly and slides inside for life-giving warmth? Well the .NET guys have done the same today by making the .NET Framework Library source code available for nerdly enjoyment.","content":"<p>Remember that scene in Star Wars when Luke (or was it Han Solo?) cuts open that crazy goat-beast thing&rsquo;s belly and slides inside for life-giving warmth? Well the .NET guys have done the same today by making the <a href=\"http:\/\/weblogs.asp.net\/scottgu\/archive\/2008\/01\/16\/net-framework-library-source-code-now-available.aspx\">.NET Framework Library source code available<\/a> for nerdly enjoyment.<\/p>\n<p>When I was learning CodeGear&rsquo;s <a href=\"http:\/\/www.codegear.com\/products\/delphi\/win32\">Delphi<\/a> (still the best tool for creating native Win32 apps I must say) having the complete source to the VCL (the Delphi framework) was the best learning tool I could have asked for. Whenever I was unsure of how to code up a certain pattern I went trolling through the source and found inspiration. Sometimes I just browsed it for fun and other times it was a life-saver when it came to debugging and tracking down hard to find issues.<\/p>\n<p>Even if you don&rsquo;t think you&rsquo;ll use it for debugging download it anyway and just browse the developer comments to see how the crew aboard a big ship like Microsoft treats their code.<\/p>"},{"title":"ASP.NET MVC Makes .NET Fun Again","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/asp-net-mvc-makes-net-fun-again\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/asp-net-mvc-makes-net-fun-again\/","updated":"2026-10-18T02:41:51+00:00","published":"2007-12-14T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"I&rsquo;ve been dabbling in the Ruby on Rails world for awhile and I&rsquo;ve always been drawn to the very clean separation of the Model-View-Controller framework, something Rails pretty much nailed in their implementation. I&rsquo;ve done a few small Rails sites here and there, played with it enough to be dangerous but I didn&rsquo;t use it enough in my daily life to really get it under my belt.","content":"<p>I&rsquo;ve been dabbling in the Ruby on Rails world for awhile and I&rsquo;ve always been drawn to the very clean separation of the Model-View-Controller framework, something Rails pretty much nailed in their implementation. I&rsquo;ve done a few small Rails sites here and there, played with it enough to be dangerous but I didn&rsquo;t use it enough in my daily life to really get it under my belt. At the same time I was doing a lot of ASP.NET work and felt like I was constantly fighting the WebForms architecture to get it to produce proper stateless standards-compliant web applications that were based around the concept of request\/response. I&rsquo;d disable ViewState, override Inits(), hack into the page lifecycle and ignore server controls so I had real control the HTML output and get back my CSS id selectors. In a very bad way WebForms reminded me of VB6 and all the hacks I had to do during my stint with that language.<\/p>\n<p>The most frustrating point came when the CSS Adapters were released and touted as some kind of panacea to those that cared about web standards when in reality they are more akin to giving a woman with a horrible breast job a big baggy sweater with a picture of a nice rack on the front. Sure, it may be a pretty picture but the scar tissue and ugly layers are still there.<\/p>\n<p>I think I got some of my faith back after I started reading <a href=\"http:\/\/blog.wekeroad.com\/\">Rob Conery&rsquo;s blog<\/a> because in him I found a Rails enthusiast who still enjoyed the many good aspects of ASP.NET and C#. Instead of just jumping ship he was bringing some of the better elements, and more importantly concepts, over to the .NET side with the <a href=\"http:\/\/www.subsonicproject.com\/\">SubSonic project<\/a>. Then he somehow got mixed up with some other crazy people like <a href=\"http:\/\/haacked.com\/\">Phil Haack<\/a>, <a href=\"http:\/\/weblogs.asp.net\/scottgu\/\">Scott Guthrie<\/a> and <a href=\"http:\/\/www.hanselman.com\/blog\/\">Scott Hanselman<\/a> and now we have the <a href=\"http:\/\/asp.net\/downloads\/3.5-extensions\/\">ASP.NET 3.5 Extensions Preview<\/a> which contains a juicy little nugget otherwise known as ASP.NET MVC.<\/p>\n<p>After wading through the bits, doing a few sample projects and generally taking their version of MVC for a walk-about I can say I&rsquo;m once again excited about .NET. Sure there are some rough spots and some areas that are a bit too &ldquo;chewy&rdquo; (you know a line of code that&rsquo;s a 100 characters long and includes at least three generics and two type casts? yeah, that&rsquo;s chewy) and design decisions that some people are taking umbrage over but all in all it feels useful, feels clean and feels like real programming.<\/p>\n<p>In an odd way I have the same feeling I had back in the day when I switched from Visual Basic to <a href=\"http:\/\/www.codegear.com\/products\/delphi\/win32\">Delphi<\/a> (which I still think is the best tool for creating native Win32 applications), like I once again have control.<\/p>","category":[{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/categories\/code\/","term":"Code","label":"Code"}},{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/tags\/.net\/","term":".Net","label":".Net"}},{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/tags\/asp.\/","term":"Asp.","label":"Asp."}},{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/tags\/microsoft\/","term":"Microsoft","label":"Microsoft"}}]},{"title":"Updated ZuneKeys","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/updated-zunekeys\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/updated-zunekeys\/","updated":"2026-10-18T02:41:51+00:00","published":"2007-11-16T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"Awhile back I wrote a wee little Delphi application to mimic WinAmp&rsquo;s Global Hotkeys in the Zune software, call ZuneKeys. With the new Zune software out I had to update ZuneKeys to work with it so if you&rsquo;re one of the three people that actually like global hotkeys go ahead and grab the new version from the above links.","content":"<p>Awhile back I wrote a wee <a href=\"https:\/\/whiskeyandcode.com\/posts\/zunekeys-global-hotkey-support-for-zune\">little Delphi application<\/a> to mimic WinAmp&rsquo;s Global Hotkeys in the Zune software, call <a href=\"https:\/\/whiskeyandcode.com\/downloads\/ZuneKeys.zip\">ZuneKeys<\/a>. With the new Zune software out I had to update ZuneKeys to work with it so if you&rsquo;re one of the three people that actually like global hotkeys go ahead and grab the new version from the above links.<\/p>\n<p>For nerds that care I had to change the window class I was searching for from &ldquo;WMPlayerAppZune&rdquo; to &ldquo;UIX Render Window&rdquo;. Long Zheng over on istartedsomething has some more interesting bits about this <a href=\"http:\/\/www.istartedsomething.com\/20071116\/microsoft-iris-uix-framework-zune\/\">whole &ldquo;UIX&rdquo; business<\/a>.<\/p>","category":{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/categories\/zune\/","term":"Zune","label":"Zune"}}},{"title":"Develop for Your Customers, not other Developers","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/develop-for-your-customers-not-other-developers\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/develop-for-your-customers-not-other-developers\/","updated":"2026-10-18T02:41:51+00:00","published":"2007-10-17T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"Recently my wife has been struggling with a web developer and he epitomizes a type that you find in specialized areas; someone that looks down upon and punishes those that aren&rsquo;t also in the field.\nA classic example of this is the music critic.","content":"<p>Recently my wife has been struggling with a web developer and he epitomizes a type that you find in specialized areas; someone that looks down upon and punishes those that aren&rsquo;t also in the field.<\/p>\n<p>A classic example of this is the music critic. They&rsquo;ll lambaste whatever popular music comes down the pipe while heaping accolades upon bands that you can barely understand, lauding praise upon the intricate chord progressions or the unique way the guitarist bent the notes on the third change, hailing it as the album of the year and declaring the lack of it&rsquo;s appreciation as more proof of our general decline into mediocrity.<\/p>\n<p>In software development this manifests itself as web sites that look horrible in Internet Explorer and have a snide comment along the lines of &ldquo;Get a Real Browser, download FireFox now to see how this page really looks&rdquo; or ugly e-mails with a top link saying, &ldquo;If you&rsquo;re using GMail\/Outlook\/Insert Hated E-Mail Program Here then click here to see a better version or use a real e-mail program.&rdquo; Another even more juvenile form is when someone requests help in an online forum and some jackass responds with, &ldquo;Well, if you had this OS\/browser\/computer\/car\/keyboard\/mouse\/console\/Internet connection then you wouldn&rsquo;t have this problem.&rdquo; Oh let me tell you how useful that is.<\/p>\n<p>The other way this manifests is when a developer gets more focused on a technology rather than the customer&rsquo;s experience. For example I love and develop CSS\/XHTML-based web sites but if you&rsquo;re transitioning from old HTML 4.01 then your new XHTML strict site had better look as good if not better than the previous version otherwise it just appears like a step backwards to the customer.<\/p>\n<p>Whenever you make a technology change, whether it&rsquo;s changing to or from a platform such as PHP, ASP.NET or Rails or it&rsquo;s adopting new standards you need to first ask, &ldquo;How is this going to benefit my customers? Are they going to lose any functionality? Are they going to gain anything that makes the inevitable transition headaches worth it&hellip; for them?&rdquo; Another important question is, &ldquo;How does this affect the majority of my customers?&rdquo;. Too often I see new features being added to support the few but in order to implement them the many are punished or worse the entire customer base is inconvenienced because the developer got a wild hair and swore some new bit of kit would make everything so much easier, yet somehow it really doesn&rsquo;t.<\/p>\n<p>I love shiny new things but it&rsquo;s important to not let all that shiny get in the way of the actual product.<\/p>"},{"title":".NET Framework Source Code Being Released","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/net-framework-source-code-being-released\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/net-framework-source-code-being-released\/","updated":"2026-10-18T02:41:51+00:00","published":"2007-10-04T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"One of the things I always loved about working with Delphi was the fact that the entire VCL framework&rsquo;s source code was shipped with the product. Being able to look at and debug into the existing framework code is an invaluable tool for both learning how things are done as well as debugging tricky issues.","content":"<p>One of the things I always loved about working with Delphi was the fact that the entire VCL framework&rsquo;s source code was shipped with the product. Being able to look at and debug into the existing framework code is an invaluable tool for both learning how things are done as well as debugging tricky issues.<\/p>\n<p>Today Microsoft announced that they&rsquo;ll be doing the same for the .NET 3.5 framework in the upcoming Visual Studio 2008 release which is awesome news. Scott Guthrie <a href=\"http:\/\/weblogs.asp.net\/scottgu\/archive\/2007\/10\/03\/releasing-the-source-code-for-the-net-framework-libraries.aspx\">has the deets<\/a>.<\/p>\n<p>While you&rsquo;ve always been able to use a tool like Lutz Roeder&rsquo;s <a href=\"http:\/\/www.aisto.com\/roeder\/dotnet\/\">Reflector<\/a> to get an approximation of the source code there are always little nuisances that get lost in the CodeDOM translation. Reading source code is really a great way to learn a language and I&rsquo;ve often found other&rsquo;s code inspiring me to write better.<\/p>\n<p>This is yet more good news for what&rsquo;s shaping up to be a pretty solid release with Visual Studio 2008. I&rsquo;ve been using the beta for awhile now and find it hard to go to back 2005 for the few times I have to.<\/p>"},{"title":"Migrations for .NET coming in SubSonic","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/migrations-for-net-coming-in-subsonic\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/migrations-for-net-coming-in-subsonic\/","updated":"2026-10-18T02:41:51+00:00","published":"2007-10-04T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"I&rsquo;m being lazy and just posting a link because I think this feature is that cool:\nSubSonic: Migrate Me\nIf you&rsquo;ve used Rails you&rsquo;ll know why this is so cool and if you haven&rsquo;t then think &ldquo;A really cool way to version your database schema and all it&rsquo;s changes and it&rsquo;s default data.","content":"<p>I&rsquo;m being lazy and just posting a link because I think this feature is that cool:<\/p>\n<p><a href=\"http:\/\/blog.wekeroad.com\/2007\/10\/03\/subsonic-migrate-me\/\">SubSonic: Migrate Me<\/a><\/p>\n<p>If you&rsquo;ve used Rails you&rsquo;ll know why this is so cool and if you haven&rsquo;t then think &ldquo;A really cool way to version your database schema and all it&rsquo;s changes and it&rsquo;s default data.&rdquo; The Rails kids shouldn&rsquo;t have all the fun. Read the article, Rob Conery will explain it much better than I ever could.<\/p>\n<p>Plus, he&rsquo;s been known to use phrases like &ldquo;<a href=\"http:\/\/blog.wekeroad.com\/2007\/09\/26\/subsonic-whats-happening-now\/\">The Tits<\/a>&rdquo; when describing software features and you just don&rsquo;t see quality writing like that just anywhere.<\/p>","category":{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/categories\/subsonic\/","term":"SubSonic","label":"SubSonic"}}},{"title":"Preventing \u201cCould not find schema\u201d for SubSonic in Visual Studio","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/preventing-could-not-find-schema-for-subsonic-in-visual-studio\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/preventing-could-not-find-schema-for-subsonic-in-visual-studio\/","updated":"2026-10-18T02:41:51+00:00","published":"2007-08-18T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"My current favorite .NET DAL\/ORM solution is SubSonic. It strikes a good balance of being helpful without hindering, partly due to it being heavily inspired by Rails as well as the creator&rsquo;s focus not only on good code but good architecture and design.","content":"<p>My current favorite .NET DAL\/ORM solution is <a href=\"http:\/\/subsonicproject.com\/\">SubSonic<\/a>. It strikes a good balance of being helpful without hindering, partly due to it being heavily inspired by Rails as well as the creator&rsquo;s focus not only on good code but good architecture and design. Another great thing about the project is that the creator, Rob Conery, does frequent screencasts explaining the nooks and crannies of SubSonic as well as writing informative, engaging and colorful posts over on <a href=\"http:\/\/spook.wekeroad.com\/\">his blog<\/a>.<\/p>\n<p>Enough praise though, this post is all about fixing an &ldquo;issue&rdquo; that annoys me. SubSonic does part of it&rsquo;s magic through the SubSonicService, which is a custom configuration section in your web or app config. Since it&rsquo;s a custom section Visual Studio won&rsquo;t give you code completion (aka Intellisense) and it&rsquo;ll spit out a ton of &ldquo;Could not find schema information for blahblahblah&rdquo; warnings. These warning are basically saying, &ldquo;I have no idea what this crap is in the web.config so you get no fancy Intellisense magic from me&rdquo;. To get back some of that magic here&rsquo;s all you have to do:<\/p>\n<ol>\n<li>\n<p>Download <a href=\"https:\/\/whiskeyandcode.com\/downloads\/SubSonicSchema.zip\">SubSonicSchema.zip<\/a> (if you right-click to download make sure you save it with an xsd extension)<\/p>\n<\/li>\n<li>\n<p>Put it in <code>C:\\Program Files\\Microsoft Visual Studio 8.0\\XmlSchemas<\/code><\/p>\n<\/li>\n<li>\n<p>Edit DotNetConfig.xsd in the same folder and add the following line:<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-xml\" data-lang=\"xml\"><span class=\"line\"><span class=\"cl\"><span class=\"nt\">&lt;xs:include<\/span> <span class=\"na\">schemaLocation=<\/span><span class=\"s\">&#34;SubSonicSchema.xsd&#34;<\/span> <span class=\"nt\">\/&gt;<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><p>(I added it right underneath the <code>&lt;xs:schema&gt;<\/code> opening tag, seems to work)<\/p>\n<\/li>\n<li>\n<p>Close Visual Studio if it&rsquo;s running, re-open, ta-da you now have Intellisense as well as no more annoying &ldquo;Could not find schema information for&hellip;&rdquo; messages.<\/p>\n<\/li>\n<\/ol>","category":{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/categories\/subsonic\/","term":"SubSonic","label":"SubSonic"}}},{"title":"A Simple Delphi rakefile","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/a-simple-delphi-rakefile\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/a-simple-delphi-rakefile\/","updated":"2026-10-18T02:41:51+00:00","published":"2007-08-16T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"Building projects has always been a pain in the arse. You want it to be simple, fast and easily reproducible, all of which are tenets of good continuous integration. When it comes to building a Delphi project I&rsquo;ve tried a whole slew of things from batch files to the Ant-based Want to very slick IDE&rsquo;s like Automated Build Studio and FinalBuilder.","content":"<p>Building projects has always been a pain in the arse. You want it to be simple, fast and easily reproducible, all of which are tenets of good continuous integration. When it comes to building a Delphi project I&rsquo;ve tried a whole slew of things from batch files to the Ant-based Want to very slick IDE&rsquo;s like Automated Build Studio and FinalBuilder. I keep coming back to simple DOS-based apps though because in my ideal world a user should be able to do a clean checkout of your code and then be able to build.<\/p>\n<p>Currently I use Want, which is a Delphi port of Java&rsquo;s Ant, .NET users will probably think of NAnt which was also a port and then heavily extended. Ant, or it&rsquo;s derivatives, is great until you need to manage a large build file and have to wade though all that xml to figure out what&rsquo;s going on. Xml is just not the best format for humans to muck about in so lately I&rsquo;ve been looking at Rake, basically Ruby&rsquo;s version of make. Maybe I&rsquo;ll whip this up into an tutorial or something more informative but for now here is a <em>very<\/em> basic build script using rake, in fact it&rsquo;s the one I use to build my ZuneKeys application:<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\"> 1\n<\/span><span class=\"lnt\"> 2\n<\/span><span class=\"lnt\"> 3\n<\/span><span class=\"lnt\"> 4\n<\/span><span class=\"lnt\"> 5\n<\/span><span class=\"lnt\"> 6\n<\/span><span class=\"lnt\"> 7\n<\/span><span class=\"lnt\"> 8\n<\/span><span class=\"lnt\"> 9\n<\/span><span class=\"lnt\">10\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"k\">def<\/span> <span class=\"nf\">compile_project<\/span><span class=\"p\">(<\/span><span class=\"n\">project_file<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">args<\/span> <span class=\"o\">=<\/span> <span class=\"s2\">&#34;-B -Q <\/span><span class=\"si\">#{<\/span><span class=\"n\">project_file<\/span><span class=\"si\">}<\/span><span class=\"s2\">&#34;<\/span><span class=\"p\">;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">result<\/span> <span class=\"o\">=<\/span> <span class=\"sx\">%x[dcc32 <\/span><span class=\"si\">#{<\/span><span class=\"n\">args<\/span><span class=\"si\">}<\/span><span class=\"sx\">]<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">if<\/span> <span class=\"n\">result<\/span> <span class=\"o\">=~<\/span> <span class=\"sr\">\/Error\/<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nb\">puts<\/span> <span class=\"n\">result<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">else<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">project_name<\/span> <span class=\"o\">=<\/span> <span class=\"n\">project_file<\/span><span class=\"o\">.<\/span><span class=\"n\">gsub<\/span><span class=\"p\">(<\/span><span class=\"sr\">\/..*\/<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&#34;&#34;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nb\">puts<\/span> <span class=\"s2\">&#34;built <\/span><span class=\"si\">#{<\/span><span class=\"n\">project_name<\/span><span class=\"si\">}<\/span><span class=\"s2\">&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">end<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"k\">end<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><span class=\"lnt\">2\n<\/span><span class=\"lnt\">3\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">file<\/span> <span class=\"s1\">&#39;ZuneKeys.exe&#39;<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"o\">[<\/span><span class=\"s1\">&#39;ZuneKeys.dpr&#39;<\/span><span class=\"p\">,<\/span> <span class=\"no\">FileList<\/span><span class=\"o\">[<\/span><span class=\"s1\">&#39;*.pas&#39;<\/span><span class=\"o\">]]<\/span> <span class=\"k\">do<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">compile_project<\/span> <span class=\"s2\">&#34;ZuneKeys.dpr&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"k\">end<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><span class=\"lnt\">2\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">task<\/span> <span class=\"ss\">:default<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"o\">[<\/span><span class=\"s1\">&#39;ZuneKeys.exe&#39;<\/span><span class=\"o\">]<\/span> <span class=\"k\">do<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"k\">end<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><span class=\"lnt\">2\n<\/span><span class=\"lnt\">3\n<\/span><span class=\"lnt\">4\n<\/span><span class=\"lnt\">5\n<\/span><span class=\"lnt\">6\n<\/span><span class=\"lnt\">7\n<\/span><span class=\"lnt\">8\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">desc<\/span> <span class=\"s2\">&#34;Remove temporary files created during compile&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"n\">task<\/span> <span class=\"ss\">:clean<\/span> <span class=\"k\">do<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">if<\/span> <span class=\"no\">File<\/span><span class=\"o\">.<\/span><span class=\"n\">exists?<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;ZuneKeys.exe&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">rm<\/span> <span class=\"s2\">&#34;ZuneKeys.exe&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">end<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"n\">rm<\/span> <span class=\"no\">FileList<\/span><span class=\"o\">[<\/span><span class=\"s1\">&#39;*.dcu&#39;<\/span><span class=\"o\">]<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nb\">puts<\/span> <span class=\"s2\">&#34;clean&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"k\">end<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><span class=\"lnt\">2\n<\/span><span class=\"lnt\">3\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-ruby\" data-lang=\"ruby\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">task<\/span> <span class=\"ss\">:release<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"o\">[<\/span><span class=\"ss\">:clean<\/span><span class=\"p\">,<\/span> <span class=\"ss\">:default<\/span><span class=\"o\">]<\/span> <span class=\"k\">do<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"> <span class=\"nb\">puts<\/span> <span class=\"s2\">&#34;release project&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"k\">end<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div>","category":[{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/categories\/code\/","term":"Code","label":"Code"}},{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/tags\/delphi\/","term":"Delphi","label":"Delphi"}}]},{"title":"ZuneKeys: Global Hotkey Support for Zune","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/zunekeys-global-hotkey-support-for-zune\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/zunekeys-global-hotkey-support-for-zune\/","updated":"2026-10-18T02:41:51+00:00","published":"2007-07-15T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"Global hotkey support for the Zune software, similar to Winamp","content":"<p>Before Zune I used <a href=\"https:\/\/winamp.com\/\">Winamp<\/a> and one of the things I really liked was it&rsquo;s global hotkey support, the ability to control the player using just hotkeys. Ever since using the Zune I&rsquo;ve found myself hitting <code>Ctrl + Alt + Home<\/code> to pause the player about a 100 times so instead of whining about it in yet another blog post I thought I&rsquo;d actually do something. It was a slow afternoon on a Friday so I whipped up this, <a href=\"https:\/\/whiskeyandcode.com\/downloads\/ZuneKeys.zip\">ZuneKeys<\/a>, global hotkey support for the Zune software.<\/p>\n<h2 id=\"install\">Install<\/h2>\n<ol>\n<li><a href=\"https:\/\/whiskeyandcode.com\/downloads\/ZuneKeys.zip\">Download ZuneKeys<\/a><\/li>\n<li>Unzip and copy somewhere, personally I use <code>C:\\Program Files\\ZuneKeys<\/code><\/li>\n<li>Run ZuneKeys.exe&hellip;<\/li>\n<li>&hellip;and Bob&rsquo;s yer uncle! Now you have global hotkey support for your Zune software.<\/li>\n<\/ol>\n<p>I&rsquo;d suggest adding ZuneKeys to your startup menu so it&rsquo;s always available.<\/p>\n<h2 id=\"the-keys\">The Keys<\/h2>\n<table>\n<thead>\n<tr>\n<th>Action<\/th>\n<th>Shortcut<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Play<\/td>\n<td>Ctrl + Alt + Insert<\/td>\n<\/tr>\n<tr>\n<td>Pause<\/td>\n<td>Ctrl + Alt + Home<\/td>\n<\/tr>\n<tr>\n<td>Stop<\/td>\n<td>Ctrl + Alt + End<\/td>\n<\/tr>\n<tr>\n<td>Previous Track<\/td>\n<td>Ctrl + Alt + Page Up<\/td>\n<\/tr>\n<tr>\n<td>Next Track<\/td>\n<td>Ctrl + Alt + Page Down<\/td>\n<\/tr>\n<tr>\n<td>Volume Up<\/td>\n<td>Ctrl + Alt + Up<\/td>\n<\/tr>\n<tr>\n<td>Volume Down<\/td>\n<td>Ctrl + Alt + Down<\/td>\n<\/tr>\n<tr>\n<td>Fast Forward<\/td>\n<td>Ctrl + Alt + Right<\/td>\n<\/tr>\n<tr>\n<td>Rewind<\/td>\n<td>Ctrl + Alt + Left<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2 id=\"how-it-works\">How it Works<\/h2>\n<p>I&rsquo;m basically sending the same commands that your fancy media keyboards sends, except I don&rsquo;t use media keyboards as they take up entirely too much space on my already cramped desk. Nothing too magically here. I&rsquo;m pretty sure the Winamp one actually sends Winamp messages that it knows how to respond to but since the Zune software doesn&rsquo;t have anything like that I&rsquo;m faking it.<\/p>\n<p>There is no customization of hotkeys and it could probably do a lot more but I wanted to keep it as tiny as possible since I already seem to have a 100 other things running in the background trying to compete for my system&rsquo;s resources. If someone besides me actually uses this puppy I&rsquo;m sure I could accommodate customized keys or other small enhancements.<\/p>\n<p>This works with the Zune right now because that&rsquo;s where I needed it but it could easily be adapted to work for Windows Media Player, iTunes, Winamp, etc.<\/p>\n<p>Oh, it seems to work just fine under Vista and XP.<\/p>\n<h2 id=\"the-open-source\">The (Open) Source<\/h2>\n<p>It&rsquo;s written in <a href=\"http:\/\/www.codegear.com\/products\/delphi\/win32\">Delphi<\/a> as a standard Win32 application. Since it&rsquo;s Delphi that means the only thing you need is the EXE, no .NET or Java Virtual Machine needed here. Since I avoided using the VCL and went old-school Windows app it&rsquo;s only 30.5kb instead of the more usual 300kb Delphi app. If you&rsquo;d like the source just ask, I&rsquo;ll put it some place public or give you access to my subversion repository. A special thanks to <a href=\"http:\/\/www.iconbuffet.com\/\">IconBuffet<\/a> as the icon I&rsquo;m using is from one of their &ldquo;Free Delivery&rdquo; icon sets, Dresden Symphony.<\/p>\n<p><a href=\"https:\/\/github.com\/shawnoster\/ZuneKeys\">ZuneKeys source on Github<\/a><\/p>\n<p><strong>UPDATED:<\/strong> Some people noticed that the source zip was missing ZuneKeys.inc. Sorry for not having it there the first time. I&rsquo;ve updated the download with all the files I have in my source folder. I&rsquo;ll probably be moving this to Github or CodePlex so it&rsquo;s more formally hosted and people can share their work.<\/p>","category":{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/categories\/zune\/","term":"Zune","label":"Zune"}}},{"title":"Running a .NET 2.0 App from a Network Share","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/running-a-net-2-0-app-from-a-network-share\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/running-a-net-2-0-app-from-a-network-share\/","updated":"2026-10-18T02:41:51+00:00","published":"2007-07-07T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"Just ran into an issue trying to run a simple .NET 2.0 file writing command-line app across a network share. No matter how much beating we couldn&rsquo;t get it to run until we ran across this little batch file in the comments on the .","content":"<p>Just ran into an issue trying to run a simple .NET 2.0 file writing command-line app across a network share. No matter how much beating we couldn&rsquo;t get it to run until we ran across this little batch file in the comments on the .NET Security Blog post, <a href=\"http:\/\/blogs.msdn.com\/shawnfa\/archive\/2004\/12\/30\/344554.aspx\">Using CasPol to Fully Trust a Share<\/a>:<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-powershell\" data-lang=\"powershell\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">call<\/span> <span class=\"k\">%<\/span><span class=\"n\">windir<\/span><span class=\"k\">%<\/span><span class=\"n\">Microsoft<\/span><span class=\"p\">.<\/span><span class=\"py\">NETFrameworkv2<\/span><span class=\"p\">.<\/span><span class=\"py\">0<\/span><span class=\"p\">.<\/span><span class=\"py\">50727caspol<\/span> <span class=\"n\">-q<\/span> <span class=\"n\">-m<\/span> <span class=\"n\">-ag<\/span> <span class=\"mf\">1.2<\/span> <span class=\"n\">-url<\/span> <span class=\"k\">%<\/span><span class=\"mf\">1<\/span><span class=\"p\">*<\/span> <span class=\"n\">FullTrust<\/span> <span class=\"n\">-n<\/span> <span class=\"k\">%<\/span><span class=\"mf\">1<\/span> <span class=\"n\">-d<\/span> <span class=\"s2\">&#34;FullTrust granted to: %1&#34;<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><p>I dropped the code into a batch file called <code>trustshare.bat<\/code> and ran it like this:<\/p>\n<div class=\"highlight\"><div class=\"chroma\">\n<table class=\"lntable\"><tr><td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code><span class=\"lnt\">1\n<\/span><\/code><\/pre><\/td>\n<td class=\"lntd\">\n<pre tabindex=\"0\" class=\"chroma\"><code class=\"language-powershell\" data-lang=\"powershell\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">trustshare<\/span><span class=\"p\">.<\/span><span class=\"py\">bat<\/span> <span class=\"p\">\/\/<\/span><span class=\"n\">machine<\/span><span class=\"p\">\/<\/span><span class=\"n\">sharename<\/span>\n<\/span><\/span><\/code><\/pre><\/td><\/tr><\/table>\n<\/div>\n<\/div><p>Suddenly the three hours of hair pulling finally ended. The batch file needs to be run on each machine that&rsquo;s attempting to run the application, not on the machine that&rsquo;s actually sharing the application.<\/p>\n<p>While I really enjoy .NET for web applications I go crazy trying to use them as stand-alone desktop apps. I much prefer CodeGear&rsquo;s Delphi when creating standard Win32 apps, you get a single EXE and don&rsquo;t have to worry about a secondary layer of security permissions beyond the file system during deployment.<\/p>"},{"title":"Using XP-style, 32-bit png\u2019s as icons in Delphi","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/using-xp-style-32-bit-pngs-as-icons-in-delphi\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/using-xp-style-32-bit-pngs-as-icons-in-delphi\/","updated":"2026-10-18T02:41:51+00:00","published":"2007-05-11T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"There are some pretty great looking icons out there, with lovely drop shadows and alpha-blending, problem is they look pretty bad in Delphi since it doesn&rsquo;t fully support them. Below is how I use XP-style, 32-bit png images as icons inside my Delphi applications.","content":"<p>There are some pretty great looking icons out there, with lovely drop shadows and alpha-blending, problem is they look pretty bad in Delphi since it doesn&rsquo;t fully support them. Below is how I use XP-style, 32-bit png images as icons inside my Delphi applications.<\/p>\n<h2 id=\"create-a-resource-file\">Create a resource file<\/h2>\n<ol>\n<li>\n<p>Get your image into an .ico format. I use <a href=\"http:\/\/www.towofu.net\/soft\/e-aicon.php\" title=\"@icon sushi\">icon sushi<\/a> to convert png images into icos.<\/p>\n<\/li>\n<li>\n<p>Create a new text file, save it as icons.rc (you can call it whatever you want).<\/p>\n<\/li>\n<li>\n<p>Edit the file and for each icon create an icon resource entry, like this:<\/p>\n<pre tabindex=\"0\"><code class=\"language-res\" data-lang=\"res\">icon_edit ICON &#34;edit.ico&#34;\n<\/code><\/pre><ul>\n<li><em>icon_edit<\/em> is the name of the resource, this is how you&rsquo;ll refer to it in code when you load it.<\/li>\n<li><em>ICON<\/em> is the type of resource, in this case&hellip; well, you get it.<\/li>\n<li><em>&ldquo;edit.ico&rdquo;<\/em> is the name of the icon file and it can include a path. A common pattern I use is to put all my icons in a folder, imaginatively named &ldquo;icons&rdquo; and then I include them like this:<\/li>\n<\/ul>\n<pre tabindex=\"0\"><code class=\"language-res\" data-lang=\"res\">icon_edit ICON &#34;.iconsedit.ico&#34;icon_copy ICON &#34;.iconseditcopy.ico&#34;icon_paste ICON &#34;.iconseditpaste.ico&#34;\n<\/code><\/pre><\/li>\n<li>\n<p>Compile the resource script into a resource file. I use Borland&rsquo;s Resource Compiler, brcc32. To make it so I don&rsquo;t have to drop down to DOS all the time I create a little batch file that I can double-click. It looks like this:<\/p>\n<pre tabindex=\"0\"><code class=\"language-res\" data-lang=\"res\">brcc32 icons.rc\n<\/code><\/pre><\/li>\n<li>\n<p>Ie the resource file in your project. You can include a resource in any of your unit files but I prefer to include it in the unit from where I&rsquo;ll be using it, such as the main form or a datamodule. Include it like this:<\/p>\n<pre tabindex=\"0\"><code class=\"language-res\" data-lang=\"res\">{$R icons.res}\n<\/code><\/pre><\/li>\n<\/ol>\n<h2 id=\"prepare-your-form\">Prepare your Form<\/h2>\n<ol>\n<li>\n<p>Add a <code>TImageList<\/code> to your form. Change the <code>Width<\/code> &amp; <code>Height<\/code> properties to match the size of the icons you want to load (32x32 for example).<\/p>\n<\/li>\n<li>\n<p>Load this file: <a href=\"https:\/\/whiskeyandcode.com\/downloads\/uXPIcons.zip\">uXPIcons.zip<\/a>. It has routines that will enable your <code>TImageList<\/code> to support 32-bit XP style icons. I can&rsquo;t take any credit for these routines. I found them on someone elses site describing the exact same thing I am but I can&rsquo;t find it anymore.<\/p>\n<\/li>\n<li>\n<p>Unzip and add the uXPIcons.pas unit to your project.<\/p>\n<\/li>\n<li>\n<p>Create a new procedure called <code>InitializeImageList()<\/code> or some other fun name.<\/p>\n<\/li>\n<li>\n<p>Add the following code to your new procedure:<\/p>\n<pre tabindex=\"0\"><code class=\"language-delphi\" data-lang=\"delphi\">ConvertTo32BitImageList(ImageList1);AddIconResourceToImageList(&#39;icon_edit&#39;, ImageList1);AddIconResourceToImageList(&#39;icon_copy&#39;, ImageList1);\n<\/code><\/pre><\/li>\n<li>\n<p><code>AddIconResourceToImageList<\/code> returns an integer which is the index of the icon just added, which can be used to set the <code>GlyphIndex<\/code> for any control that takes both an <code>ImageList<\/code> and a <code>GlyphIndex<\/code><\/p>\n<\/li>\n<li>\n<p>Call <code>InitializeImageList()<\/code> from your <code>FormCreate()<\/code>.<\/p>\n<\/li>\n<li>\n<p>Run it and rock.<\/p>\n<\/li>\n<\/ol>\n<p>You&rsquo;ll notice is that now your main application icon has been replaced by the first icon in your resource file. My suggestion is to just make sure your application icon is first in your resource file. It actually works better for me since I often have to create versions of my applications with different main icons and being able to swap them out via different resource files using a build script is much easier.<\/p>","category":[{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/categories\/delphi\/","term":"Delphi","label":"Delphi"}},{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/tags\/code\/","term":"Code","label":"Code"}},{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/tags\/delphi\/","term":"Delphi","label":"Delphi"}}]},{"title":"What I Have Learned About Writing Good Code","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/what-ive-learned-about-writing-good-code\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/what-ive-learned-about-writing-good-code\/","updated":"2026-10-18T02:41:51+00:00","published":"2007-05-03T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"There are lessons you learn in school and there are the things you learn along the way. I&rsquo;ve been developing software for 25 years, since I was 8, starting with a book called &ldquo;Your First BASIC Program&rdquo; that my dad bought me because we had a PC while all my friends were playing StarBlazers on their Apple IIs.","content":"<p>There are lessons you learn in school and there are the things you learn along the way. I&rsquo;ve been developing software for 25 years, since I was 8, starting with a book called &ldquo;<a href=\"https:\/\/www.goodreads.com\/book\/show\/4488063-your-first-basic-program\">Your First BASIC Program<\/a>&rdquo; that my dad bought me because we had a PC while all my friends were playing StarBlazers on their Apple IIs. He said if I wanted to play games then I could write one myself. At the time I was a bit disappointed (OK, crushed) but now&hellip; well, Dad, thank you.<\/p>\n<p>These are some of the things I didn&rsquo;t learn in school, but wish I had:<\/p>\n<h2 id=\"use-version-control\">Use Version Control<\/h2>\n<p>Even if you&rsquo;re a solo developer get into the habit of using a version control system. For one it gets you used to the concepts of version control which you&rsquo;ll definitely need if you work with a larger team and secondly it offers another level of protection. My current favorite is <a href=\"http:\/\/subversion.tigris.org\/\">subversion<\/a>, it&rsquo;s easy to install, has a great command-line and GUI client and it&rsquo;s free.<\/p>\n<p>One more bit, commit often. Think of commits as &ldquo;undo checkpoints&rdquo;. You thought replacing every instance of the base class across 50 project files was a great idea but then realized your idea sorta sucks? No problem, you can restore all 50 of those files back to their pristine state. No undo buffer will help you the way a good VCS will.<\/p>\n<h2 id=\"use-the-native-naming-coding-and-formatting-style-or-when-in-rome\">Use the Native Naming, Coding and Formatting Style or &ldquo;When In Rome&rdquo;<\/h2>\n<p>Before you decide to reinvent the wheel look to the native language for hints on code formatting, variable naming, indenting and method naming. Fight the urge to use your own style or to use your favorite formatting from another language. There are a few reasons:<\/p>\n<h3 id=\"maintenance\">Maintenance<\/h3>\n<p>Some poor schmuck down the line will probably have to look at your code and they will probably disagree with your highly stylized use of brackets. At least the native style of formatting will be familiar to them as a common baseline.<\/p>\n<h3 id=\"fighting-the-ide\">Fighting the IDE<\/h3>\n<p>If you&rsquo;re using an IDE it&rsquo;ll probably have some form of code completion, with some built-in templates for basic things like loops, classes, closures, etc. Those templates will more than likely be in the &ldquo;native style&rdquo; and you&rsquo;ll either spend all your time fixing the formatting or worse you&rsquo;ll create a mishmash of your style plus the IDEs, which creates confusion.<\/p>\n<h3 id=\"avoids-fights\">Avoids Fights<\/h3>\n<p>Everyone loves to fight about how to format code, picking the native coding style means you&rsquo;re the only one with an actual real argument, everything else is just opinion.<\/p>\n<h2 id=\"sharing-code\">Sharing Code<\/h2>\n<p>Sometimes you&rsquo;ll have bits of code that don&rsquo;t work and you&rsquo;ll post a snippet on a forum or newsgroup. It&rsquo;s much easier for everyone to help out if the code looks familiar. Anytime I see some really crazy formatted code from someone asking for help I skip right over it. I don&rsquo;t have time to puzzle over their code AND their strange formatting.<\/p>\n<h2 id=\"catalog-your-knowledge\">Catalog your Knowledge<\/h2>\n<p>Whether it&rsquo;s a blog, a wiki, del.icio.us or just a big fat txt file you&rsquo;ll want a way to collect the bits. As a developer you absorb an amazing amount of information each day and you&rsquo;re bound to forget that exact command-line parameter you need to get something working. Trust me, it&rsquo;s easier to spend 5 minutes writing a blog post or tagging it in del.icio.us than to have to spend another 30 minutes later hunting it back down.<\/p>\n<h2 id=\"dont-be-a-bigot\">Don&rsquo;t Be a Bigot<\/h2>\n<p>Don&rsquo;t attack someone just because they don&rsquo;t code in your language or tool of choice. I see so much energy wasted by people putting down one language or another. Ruby on Rails developers bashing ASP.NET coders, ASP.NET users coming down on Flash programmers, Delphi developers ripping apart .NET. Every language and framework has strengths and weaknesses and given the huge number of tools there will be many ways to accomplish the same goals, none of them more correct than the other.<\/p>\n<h2 id=\"dont-become-a-framework-programmer\">Don&rsquo;t become a Framework Programmer<\/h2>\n<p>I&rsquo;ve sat through some pretty painful interviews where I asked basic programming questions only to answered with, &ldquo;well, first I&rsquo;d download this library and then&hellip;&rdquo; or &ldquo;I&rsquo;d use this helper method&hellip;&rdquo;. When I asked how they&rsquo;d do it without that library or method I either got blank looks, or my favorite answer, &ldquo;well, then it couldn&rsquo;t be done&rdquo;.<\/p>\n<p>Knowing that there are great frameworks out there, whether they be .NET, the VCL or Rails, is great, and knowing how to squeeze all the performance out of them is a worthy skill but you will always hit points where you have to go outside the framework. If you understand programming concepts you can always learn new languages pretty quickly but if all your knowledge is sunk into a single framework it&rsquo;s going to make the transition rough.<\/p>\n<p>Understanding programming as a concept vs. a set of syntax and framework calls also opens up a huge number of resources for you. Not every article will be written in your language and there is no reason to ignore a great idea just because it&rsquo;s not tailored for your framework\/language of choice.<\/p>\n<h2 id=\"dont-just-copy-and-paste-code\">Don&rsquo;t just Copy And Paste Code<\/h2>\n<p>I have a phrase I use at work that I&rsquo;m pretty sure annoys the hell out of co-workers, it goes like this, &ldquo;Don&rsquo;t just copy and paste code, instead copy, <strong>understand<\/strong> and THEN paste&rdquo;. There is a wealth of code samples out there but if you don&rsquo;t really understand what it is you are using then it&rsquo;s going to be a pain in the arse later to debug. We all have times we just want to get something working but if you don&rsquo;t really understand the code you&rsquo;re using then you&rsquo;re always going to be dependent upon someone else. It&rsquo;s also important to remember that just because it turned up on the internet doesn&rsquo;t mean it&rsquo;s actually good code.<\/p>\n<h2 id=\"understand-the-sugar\">Understand the Sugar<\/h2>\n<p>Lately I&rsquo;ve seen a few examples in Ruby, JavaScript and C# showing off some great syntactical sugar, shortcuts that make it easy to do things in one line that used to take five or six. They are impressive and definitely time saving but they come with a cost, usually in terms of performance.<\/p>\n<p>One example is working with collections in Ruby. Someone posted a snippet showing how you could replace a &ldquo;bulky, ugly for-loop&rdquo; that gathered objects that met a certain criteria and then did &ldquo;something&rdquo; to them with a single line of Ruby code. The Ruby looked sexy, it was small, it was readable, it got ohhs and ahhs. The for-loop was the underdog at 9 lines, it used nothing but the most basic language constructs. The problem was the fact that the single-line of code actually went through the collection 4 separate times while the old-school for-loop did it in a single pass.<\/p>\n<p>There are quite a few times where the sugar outweighs the performance hit but it&rsquo;s important to understand what that sugar is really doing.<\/p>\n<h2 id=\"code-for-maintenance\">Code for Maintenance<\/h2>\n<p>Pretend you&rsquo;re in that movie &ldquo;<a href=\"http:\/\/www.imdb.com\/title\/tt0209144\/\" title=\"Memento\">Memento<\/a>&rdquo; and that you forget everything about your project every night. You should be able to figure out what&rsquo;s going on the next day fairly quickly just from how the project is structured, it&rsquo;s class names and coding style. Your variable names should make sense, methods should be tidy, there shouldn&rsquo;t be 15 layers you have to drill through just to do something that should be simple.<\/p>\n<p>Here is a dirty little secret, the easier it is for someone else to understand your code the easier it is for you to hand it off. If you&rsquo;re the only one that can make sense of your code you are going to tied to that project forever. Forget getting first pick of new projects, you&rsquo;re now kept in reserve incase you have to do maintenance on your project.<\/p>\n<h2 id=\"code-for-now\">Code for Now<\/h2>\n<p>As developers we love to code for that future when we may need to add another database back-end or swap out a different rendering engine or port to a different platform. Guess what, unless those things are actually on some roadmap or written on a stone tablet they will either never happen or will happen in such a way that you&rsquo;ll end up rewriting your code anyway. I have a ton of old projects littered with extra layers of abstraction that I&rsquo;ve never needed and they&rsquo;ve gotten under foot more times than they&rsquo;ve been helpful.<\/p>\n<p>Dirty Secret: It&rsquo;s always been easier to add in a new abstraction layer than it has been to work with an existing one that was never used. If you don&rsquo;t need it right now then don&rsquo;t code for it.<\/p>\n<h2 id=\"stay-abreast-of-the-landscape\">Stay Abreast of the Landscape<\/h2>\n<p>You&rsquo;ll never know everything about programming, it&rsquo;s a constantly expanding landscape but it is a good idea to keep abreast of what&rsquo;s going on around you. One of the things that has served me best is knowing just enough about other programming areas that I usually have pretty good idea to know where to look for things.<\/p>\n<p>There is no excuse to not know a little bit about what it is going on these days. It used to be I got most of my information from magazines and newsgroups, now there are also blogs and wikis, community forums and podcasts.<\/p>\n<h3 id=\"dirty-secret-1\">Dirty Secret #1<\/h3>\n<p>Subscribe to at least two different sources that have different views. Everyone is biased and again, not everyone knows everything. Usually between an evangelist and a detractor you&rsquo;ll come close to knowing the &ldquo;real&rdquo; story about something.<\/p>\n<h3 id=\"dirty-secret-2\">Dirty Secret #2<\/h3>\n<p>Read even the boring things. We used to get a Delphi magazine at work and at first I&rsquo;d only read the articles that applied to me. I&rsquo;d ignore the database and security articles because that&rsquo;s not what I was working on at the time. Then I got bored and started reading the entire thing each month. Later, when I started working on a project that was heavy on DB and security I found I already knew a little something about both.<\/p>"},{"title":"How to Version your Software","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/how-to-version-your-software\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/how-to-version-your-software\/","updated":"2026-10-18T02:41:51+00:00","published":"2007-04-22T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"Most developers live and breath version numbers, yet there are a few that either don&rsquo;t or don&rsquo;t really have a good rule of thumb on what their versions should mean. There are also quite a few people that have to deal with versions that aren&rsquo;t developers, such as tech support, marketing and new team members.","content":"<p>Most developers live and breath version numbers, yet there are a few that either don&rsquo;t or don&rsquo;t really have a good rule of thumb on what their versions should mean. There are also quite a few people that have to deal with versions that aren&rsquo;t developers, such as tech support, marketing and new team members. For those people it&rsquo;s always a good idea for everyone to be on the same page.<\/p>\n<h2 id=\"whats-in-a-version\">What&rsquo;s in a version?<\/h2>\n<p>So you have version 1.5.4.675, what does that mean? First, the different parts are, in order, major, minor, release and build number. I first wrote this up as four separate paragraphs sharing all my golden nuggets of wisdom but realized in this day and age sometimes the Cliff-Notes version is better. Here is what the various parts of a version number mean and when they should be incremented:<\/p>\n<h3 id=\"major\">Major<\/h3>\n<ul>\n<li>All features across the same version should be either 100% compatible or in rare conditions gracefully degrade.<\/li>\n<li>File formats should be compatible, all 1.x versions should open, save and edit 1.x versions.<\/li>\n<li>For commercial products all updates in the 1.x line should be free<\/li>\n<li>Only release a new major version if;\n<ul>\n<li>the flow of the application has been noticeably changed,\n<ul>\n<li>there are a significant number of new high-visibility, high-usability features,<\/li>\n<li>the user interface has drastically changed.<\/li>\n<li>New major versions should always be able to import or open older versions.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>One key point is that only new highly usable features should mark a new major version. New major versions usually mean an upgrade cost and nothing is more annoying than buying a new version only to find the new features are only useful to about 1% of the install base. I&rsquo;ve seen several products try to push a new version with inflated features that don&rsquo;t actually offer any benefit.<\/p>\n<h3 id=\"minor\">Minor<\/h3>\n<ul>\n<li>New non-breaking small feature, meaning it still works with other version with the same major version.<\/li>\n<li>Bug fixes that apply to everyone.<\/li>\n<li>You&rsquo;ll want everyone to be running the latest minor version so be prepared to make this available to everyone.<\/li>\n<li>Tech support should usually make sure the end-user is on the latest minor version before going farther. *\nInstalling the newest minor version should be painless. All user settings should transfer over seamlessly.<\/li>\n<\/ul>\n<h3 id=\"release\">Release<\/h3>\n<p>This gets a little murky for some and there are a lot of schools of thought on this one, here is mine:<\/p>\n<ul>\n<li>Represents the release of the current major.minor version.<\/li>\n<li>Increase the release when you do small, infrequently encountered bug fixes.<\/li>\n<li>Not everyone needs to be on the latest release, only those affected by certain issues.<\/li>\n<li>If you do Betas and Release Candidates this is the place to note that. If you release RC1 as version 2.5.0 and someone finds a bug you update the release to 2.5.1.<\/li>\n<li>Resets back to 0 every time the minor version changes.<\/li>\n<\/ul>\n<p>That last point is where a lot of people get into knife-fights. Some think release should mean the number of times a product has actually been &ldquo;released&rdquo; into the public. If that&rsquo;s how you think then by all means go for it. Personally I think of it as a version number for the version number, in other words, how many times did I release version 3.1?<\/p>\n<h3 id=\"build\">Build<\/h3>\n<ul>\n<li>Always increments.<\/li>\n<li>Never gets reset.<\/li>\n<li>Most useful for bug reporting.<\/li>\n<li>Should only get incremented by the &ldquo;official&rdquo; build box.<\/li>\n<\/ul>\n<p>The last point might need some explaining. For a solo developer this just means each time you build the software from your machine. For a large team though, with each developer probably compiling the application a few hundred times each day, this build number would get big fast as well as quickly lose it&rsquo;s meaning. Instead, developers on a team usually have one machine that is the official build machine, where nothing but the compiler and any needed libraries and components are installed. This insures a consistent, clean, known build each time.<\/p>\n<p>And Bob&rsquo;s your uncle. Pretty basic stuff. While there are different schools of thoughts on versioning one thing that should be clear is that everyone on your team, including managers, marketing, support and developers on other teams, should all be on the same page when it comes to versions.<\/p>"},{"title":"User Interface Is As Important As Code","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/user-interface-is-as-important-as-code\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/user-interface-is-as-important-as-code\/","updated":"2026-10-18T02:41:51+00:00","published":"2007-03-07T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"Ever hear the phrase, &ldquo;lipstick on a pig&rdquo;? It applies to a vain attempt to make something ugly look pretty, as in &ldquo;putting a fresh coat of paint on that water-damaged, termite-eaten, water leaking house is like putting lipstick on a pig.&rdquo;","content":"<p>Ever hear the phrase, &ldquo;lipstick on a pig&rdquo;? It applies to a vain attempt to make something ugly look pretty, as in &ldquo;putting a fresh coat of paint on that water-damaged, termite-eaten, water leaking house is like putting lipstick on a pig.&rdquo;<\/p>\n<p>The software world often has the opposite problem, let&rsquo;s call it &ldquo;a swan wearing galoshes&rdquo;. There are an amazing number of great software applications out there that I don&rsquo;t give a second look at because their user interface is horrible. Everything from inconsistently positioned buttons, ugly icons, poor spelling, cramped interfaces, badly explained features or hideous splash screens. By that same token there are also quite a few products and applications that do get used simply because they look good, even though they might not work quite as well as their ugly competitor.<\/p>\n<p>One of the reasons for this is because developers are usually horrible designers. While we can coax the most amazing things out of a few lines of code we often can&rsquo;t pair two colors together in a pleasing way. Worse is that many times developers think they are actually artists&hellip; and they&rsquo;re not. They&rsquo;ll beam at you while they show off the latest splash screen or icon and you&rsquo;ll be trying to hide your sudden need to gouge out your eyes.<\/p>\n<p>Another reason is just time, developers will get so excited creating a feature that they&rsquo;ll just drop buttons all over an interface. Perhaps they&rsquo;re a control freak and they&rsquo;ll feel the strong need to make every single option a control on the main form. Perhaps they just don&rsquo;t care, as long as it works, what does it matter how it looks? Well, if that reasoning applied I doubt there&rsquo;d so many different brands, models, colors and types of cars. Perhaps that person really doesn&rsquo;t care how it looks, then again they are probably wearing bland or ill-fitting clothing, perhaps slightly stained, most likely not matching.<\/p>\n<p>The sad thing is a lot of these issues can be avoided with just a little effort.<\/p>\n<ol>\n<li>\n<p>Think of the UI from the beginning. This means both in terms of usability, design, time and budget. Don&rsquo;t leave this part towards the end. Actually add it to your task list with a real amount of time instead of just assuming the UI features will magically appear at the end.<\/p>\n<\/li>\n<li>\n<p>Don&rsquo;t use temp images or icons, even as placeholders. In the software world there is no such thing as a temporary placeholder. Pick a silly splash screen or funny icon or just a &ldquo;quick button for testing&rdquo; and there is a good chance your application will go out the door just like that. People grow used to things rather quickly, even the most hideous of icons. They will also mentally check that off a &ldquo;to-do&rdquo; list in their head so if you later say you need to spend some budget on a graphic designer they&rsquo;ll usually just say, &ldquo;what about what you already have?&rdquo;, even if it does cause the elderly to void their bowels.<\/p>\n<\/li>\n<li>\n<p>Use stock icons. There are several great icon sets available for purchase these days, as well as custom icon design. Visual Studio 2005 even comes with a huge set of high quality icons for use. Please, use these. View the price of the icons not as &ldquo;some pretty things&rdquo; but as you would a component. I&rsquo;ve spent anywhere from $50 to $500 on various development tool add-ons and dropping $49 for some icons seems like a pretty good deal.<\/p>\n<p>Do not attempt to make your application look different by using your own custom icons unless yours are actually good. I&rsquo;ve seen apps where the toolbar is littered with mutant variations of standard open\/save icons with some vile gradient or abstract take on &ldquo;Open&rdquo;. All of those fail because while you may enjoy making your app look like some Dali painting your users would much rather have a consistent look and feel, including icons, across all of their applications.<\/p>\n<p>Here are a few links to get you started:<\/p>\n<ul>\n<li><a href=\"http:\/\/stockicons.com\/\" title=\"StockIcons\">StockIcons<\/a><\/li>\n<li><a href=\"http:\/\/www.iconbuffet.com\/\" title=\"IconBuffet\">IconBuffet<\/a><\/li>\n<li><a href=\"http:\/\/iconshoppe.com\/\" title=\"IconShoppe\">IconShoppe<\/a><\/li>\n<li><a href=\"http:\/\/www.glyfx.com\" title=\"glyFX\">glyFX<\/a><\/li>\n<\/ul>\n<\/li>\n<li>\n<p>Use the OS as a guide. While you might not be able to afford a designer I bet the devs of your OS could. If you&rsquo;re stuck on how certain controls should work or look then go to your OS and find something roughly similar. If you have other applications that you like the look of by all means get inspired by them, though if they have a distinctive interface be careful not to rip it off.<\/p>\n<\/li>\n<li>\n<p>Be consistent. If one option dialog has all the labels ending in a colon (like &ldquo;Password:&rdquo;) make sure EVERY dialog in your application follows that convention. If one form has all of it&rsquo;s controls 8 pixels from the left make sure ALL of them do. Even if you hate how the original forms look you still need to be consistent, or change all of them. Nothing makes an application look more shoddy than dialogs that all look slightly different.<\/p>\n<\/li>\n<\/ol>\n<p>You know how you can tell when someone has slept in the same clothes they&rsquo;re wearing? How no amount of smoothing and splashing of water and combing of hair really gets rid of that disheveled look? That&rsquo;s how an application that isn&rsquo;t consistent looks, you may not notice it at first but it is making an impression, and not usually a good one.<\/p>\n<p>Given the stiff competition in the software world today you really can&rsquo;t afford to release ugly applications anymore.<\/p>"},{"title":"TortoiseSVN global ignore pattern for Visual Studio and Delphi","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/tortoisesvn-global-ignore-pattern-for-visual-studio-and-delphi\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/tortoisesvn-global-ignore-pattern-for-visual-studio-and-delphi\/","updated":"2026-10-18T02:41:51+00:00","published":"2007-01-05T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"Seems I&rsquo;m reinstalling all the time and I commonly forget my global ignore pattern for svn. Here it is for future me:\n*bin *obj RECYCLER Bin *.user *.suo *.dcu __history ModelSupport_* *.rsm thumbs.db This pattern is useful for Visual Studio and Delphi development, though if you&rsquo;re checking in third-party Delphi components be sure you have the full source, otherwise you may need to pull the *.","content":"<p>Seems I&rsquo;m reinstalling all the time and I commonly forget my global ignore pattern for svn. Here it is for future me:<\/p>\n<pre tabindex=\"0\"><code>*bin *obj RECYCLER Bin *.user *.suo *.dcu __history ModelSupport_* *.rsm thumbs.db\n<\/code><\/pre><p>This pattern is useful for Visual Studio and Delphi development, though if you&rsquo;re checking in third-party Delphi components be sure you have the full source, otherwise you may need to pull the *.dcu part of the pattern.<\/p>","category":{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/categories\/delphi\/","term":"Delphi","label":"Delphi"}}},{"title":"FinalBuilder 5 & Automated Build Studio 2.2","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/finalbuilder-5-automated-build-studio-2-2\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/finalbuilder-5-automated-build-studio-2-2\/","updated":"2026-10-18T02:41:51+00:00","published":"2006-11-30T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"A few review notes, comparing two popular automated build tools, FinalBuilder 5.0 and Automated Build Studio 2.2. These are just notes I&rsquo;m making as I try and port an old WANT script (like ANT, but more focused on Delphi). I&rsquo;m still trying to decide which one I like better and these notes are to help me, and possibly you, decide.","content":"<p>A few review notes, comparing two popular automated build tools, <a href=\"http:\/\/www.finalbuilder.com\/finalbuilder.aspx\" title=\"FinalBuilder 5.0 Home Page\">FinalBuilder 5.0<\/a> and <a href=\"http:\/\/www.automatedqa.com\/products\/abs\/index.asp\" title=\"Automated Build Studio Home Page\">Automated Build Studio 2.2<\/a>. These are just notes I&rsquo;m making as I try and port an old <a href=\"http:\/\/sourceforge.net\/projects\/want\/\" title=\"WANT Home Page\">WANT<\/a> script (like ANT, but more focused on Delphi). I&rsquo;m still trying to decide which one I like better and these notes are to help me, and possibly you, decide.<\/p>\n<h3 id=\"the-points\">The Points:<\/h3>\n<ul>\n<li><strong>1<\/strong> means &ldquo;nice feature&rdquo; or &ldquo;that&rsquo;s nicely implemented&rdquo;.<\/li>\n<li><strong>2<\/strong> means &ldquo;rocking feature&rdquo; or &ldquo;that was implemented well&rdquo;.<\/li>\n<li><strong>3<\/strong> means &ldquo;killer feature&rdquo; or &ldquo;this is how software is supposed to be done.&rdquo;<\/li>\n<\/ul>\n<p>One of the first things I wanted to do was create a group of actions for checking out the latest code. I quickly found it in ABS&rsquo;s &ldquo;Standard&rdquo; category while I had to resort to using the Filter box in FB to finally find it under &ldquo;Flow Control&rdquo;. While it may be a flow control action I never would have looked there so, <strong>ABS 1<\/strong>.<\/p>\n<p>The Subversion Checkout action in FB is non-intuitive. It asks for a Source and Destination. Do those parameters make sense to anyone that has actually used svn? ABS kicks it&rsquo;s butt all over the place on this, asking for what you would expect: URL and Work folder. <strong>ABS 2<\/strong>.<\/p>\n<p>FB has a cool variable picker that shows you all the built-in variables as soon as you type a %. This is great except that a) you have to know that variables start with % and b) you can&rsquo;t use the mouse to click on a variable to select it. ABS has a button you can click to show a list of all variables available. While this may be a little more cumbersome if you know exactly what you&rsquo;re looking for it is much more helpful. <strong>ABS 1<\/strong>.<\/p>\n<p>Both products fail to show you what the actual value of the built-in variables are though. For example I&rsquo;m trying to specify a project file for a HTML Help Compiler project and I know I want it relative to my build file but do I specify a backslash after <code>%FBPROJECTDIR%<\/code> or not? Same with ABS. No points to either.<\/p>\n<p>I had to specify the path the the HTML Help Compiler in FB while ABS just seems to know. <strong>ABS 1<\/strong>.<\/p>\n<p>When you run scripts in FB you can stay in the &ldquo;Design View&rdquo;, with a progress bar appearing next to each action as it processes. This is nice for when you&rsquo;re building\/debugging your scripts. ABS takes you automatically to it&rsquo;s Log and Summary screen instead. While you still get a step-by-step breakdown of what it&rsquo;s doing it takes you out of the context of your script. You can prevent ABS from automatically switching and it&rsquo;ll show you what step it&rsquo;s currently on but if something fails you can&rsquo;t tell from Macro pane which operation failed. <strong>FB 1<\/strong>.<\/p>\n<p>Both products have a detailed report of the last build status but ABS seems to want to always compare it against the last successful macro run. I&rsquo;m just starting with these products but I fail to see the use. Personally it just takes up space and the good news is you can remove it. While I can configure ABS to be more to my liking I always feel you&rsquo;ve gone back a step in usability anytime the user has to reconfigure the UI. <strong>FB 1<\/strong>.<\/p>\n<p>Both failed to pick up the user override variables in BDS 2006. If you have <a href=\"http:\/\/www.remobjects.com\/\" title=\"RemObjects Home Page\">RemObjects<\/a> installed you probably also have an Everwood and RemObjects SDK user override environment variables that are used inside your library path like this $(Everwood)Bin, etc. Both ABS and DB choked on this and I&rsquo;m still waiting for a resolution. RemObjects is a pretty popular library for Delphi so I doubt I&rsquo;m the first to hit this. On the plus side, FB did leave me with a much better error message of &ldquo;Error expanding variables in Library Path : Variable : Everwood - does not exist!&rdquo; instead of ABS&rsquo;s &ldquo;Fatal: F1026 File not found: &lsquo;uROClasses.dcu&rsquo;&rdquo;. I&rsquo;m giving <strong>FB 1<\/strong> for the better message. If either of the products had successfully compiled while the other failed that would have been an instant 3 points but sadly they both dropped the ball.<\/p>\n<p><em>I&rsquo;m still reviewing the products so this page will be updated after I make it past compiling my project.<\/em><\/p>"},{"title":"Digital Dark Ages","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/digital-dark-ages\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/digital-dark-ages\/","updated":"2026-10-18T02:41:51+00:00","published":"2006-11-22T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"We are still in the digital dark ages, at least as far as media goes. Let&rsquo;s explore just how ugly it is currently:\nDRM (Digital Rights Management) DRM is supposed to be about managing the rights of digital assets yet it really has nothing to do with &ldquo;rights&rdquo; and everything to do with market lock.","content":"<p>We are still in the digital dark ages, at least as far as media goes. Let&rsquo;s explore just how ugly it is currently:<\/p>\n<h2 id=\"drm-digital-rights-management\">DRM (Digital Rights Management)<\/h2>\n<p>DRM is supposed to be about managing the rights of digital assets yet it really has nothing to do with &ldquo;rights&rdquo; and everything to do with market lock. Since no two DRM systems are interchangeable this means you&rsquo;re not just paying for the music, you&rsquo;re also paying for the device. Imagine buying a CD that only works in a Kenwood stereo and having to buy it again if you wanted to play it at home in your Toshiba CD player? If I buy a track at iTunes then I can&rsquo;t play it on my Zune. Even if I buy a track from the Zune Marketplace then I still can&rsquo;t play it on my Sonos. If I really wanted to play it all three places I&rsquo;d have to buy it three times.<\/p>\n<p>You, as a consumer, have NO digital rights.<\/p>\n<p>Until you can buy music from any source, be it iTunes, Zune Marketplace, Yahoo! Music, or any of a handful of others and play it back on any device, we will still be in the digital dark ages.<\/p>\n<h2 id=\"digital-asset-prices\">Digital Asset Prices<\/h2>\n<p>I can buy a new album on iTunes for $9.99. I don&rsquo;t get anything special for the $9.99 nor do I even get to pick the music quality BUT I do have the added bonus of only being able to play it back on my iPod (sarcasm folks).<\/p>\n<p>On the other hand I can buy the same album on CD at BestBuy for $9.99 or cheaper if I use one of their ubiquitous %10 coupons and now I have the CD, the case and some cool\/dorky booklet. I can rip that CD at any quality I want and play it on almost anything made in the last 5 years.<\/p>\n<p>The only thing I can gather from this is that the record companies still view digital as a threat and they really don&rsquo;t want you buying digital anything. They&rsquo;ve allowed you to buy their content online only as a stopgap measure but they want you in the mall buying music. Either they have some kind of Faustian deal with CD manufactories or they truly don&rsquo;t understand this new fangled digital age.<\/p>\n<p>Funny thing is that I&rsquo;d be willing to pay either $9.99 for non-DRM&rsquo;d music or $4.99 for music with DRM. What I&rsquo;m NOT willing to do is pay more money for online music when I get less than what I can get at the local music store. Until digital asset prices reflect the quality of goods that the consumer receives we&rsquo;ll still be in the dark ages.<\/p>\n<h2 id=\"albums\">Albums<\/h2>\n<p>Notice how albums are still generally 8 to 12 tracks long? Notice how they still fit neatly on a CD? How some new ones still have the concept of an A and B side, a hold-over from the tape cassette days? Every once in awhile you&rsquo;ll see an artist try something different but for the most part digital is still on the fringe, even with the massive market that the iPod, and all it represents, holds.<\/p>\n<p>Where are the $2.99 mini-albums, each with 2 or 3 tracks? I&rsquo;m not talking a single with some cutting room floor tracks thrown on but a whole new way of expressing a concept. Imagine three mini-albums, labeled, &ldquo;The Good&rdquo;, &ldquo;The Bad&rdquo;, &ldquo;The Ugly&rdquo; with the tracks on each reflecting a specific theme? What about jam bands releasing their live show audio on some Marketplace service, with a discount to ticket holders? How about a cancer drive where instead of a wrist band you get an unheard or remixed track that you can then share?<\/p>\n<p>Of course the only way these ideas could actually work would be an industry-wide accepted DRM solution that actually valued the consumer&rsquo;s rights as much as the artist&rsquo;s and was supported by a pricing structure that didn&rsquo;t gouge consumers. Which leads us back to the simple fact that we&rsquo;re still in the dark ages.<\/p>\n<h2 id=\"is-there-any-hope\">Is There Any Hope?<\/h2>\n<p>The biggest road-block to a lot of progress is the current DRM\/Device lock model, not DRM itself. There will always be people that want to get something for nothing and DRM is supposed to help prevent that but it should never be at such a huge expense to the consumer.<\/p>\n<p>The only hope is that consumers do what they&rsquo;ve always done in a capitalistic society, vote with their dollars. These are some of the ways I &ldquo;vote&rdquo;:<\/p>\n<ul>\n<li>Avoid buying music from any online service that limits what you can reasonably do with your media.<\/li>\n<li>Before pulling the trigger on that iTunes or Zune Marketplace purchase look for the actual physical CD. I bet you can find it online used for cheaper than $9.99 or even new at your local BestBuy. Buy it, rip it and resell it if you like.<\/li>\n<li>Support sites like <a href=\"http:\/\/www.emusic.com\/\">emusic.com<\/a>. While you can&rsquo;t pick the quality you CAN do whatever you want with the music. It&rsquo;s straight MP3 format with no DRM so it&rsquo;ll play on your iPod, Zune, Creative Zen, music-enabled phone, Media Center, Sonos, MP3-enabled car stereo and you can burn it to a CD as many times and as many ways as you like.<\/li>\n<li>I would say check out the Russian site, allofmp3.com, but now that VISA and MasterCard have been pressured to drop support it&rsquo;s pretty much dead in the water. Check out <a href=\"http:\/\/www.gomusic.ru\/\">GoMusic<\/a> instead.<\/li>\n<\/ul>\n<p>I&rsquo;m sure there are other creative ways but those work for me. I&rsquo;ll gladly accept, and pay for, DRM the day it works across all my devices seamlessly without loss of quality and I&rsquo;m charged a fair price. Until then&hellip; it&rsquo;s the dark ages.<\/p>"},{"title":"A Distiller Knock-Off","link":{"@attributes":{"rel":"alternate","type":"text\/html","href":"https:\/\/whiskeyandcode.com\/posts\/a-distiller-knock-off\/"}},"id":"https:\/\/whiskeyandcode.com\/posts\/a-distiller-knock-off\/","updated":"2026-10-18T02:41:51+00:00","published":"2006-09-23T00:00:00+00:00","author":{"name":"Shawn Oster","uri":"https:\/\/whiskeyandcode\/","email":"shawn.oster@gmail.com"},"rights":"[CC BY-NC-SA 4.0](https:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/deed.en)","summary":"One of the software projects I work on involves printing color-coded, barcoded labels. Yes, exactly, the height of fun. Often I need to validate that a code change I just made hasn&rsquo;t completely messed up the rendering engine. Because resolution is a huge issue in things like barcodes I need to actually print through a printer driver vs.","content":"<p>One of the software projects I work on involves printing color-coded, barcoded labels. Yes, exactly, the height of fun. Often I need to validate that a code change I just made hasn&rsquo;t completely messed up the rendering engine. Because resolution is a huge issue in things like barcodes I need to actually print through a printer driver vs. just doing a screen preview. Being a good recycling citizen I hate wasting paper, hence where Adobe&rsquo;s Acrobat Distiller and my cheap ass nature come into the picture. I like the concept of Distiller, I don&rsquo;t like paying for it.<\/p>\n<p>So, I took a bunch of freely available tools, namely <a href=\"http:\/\/www.cs.wisc.edu\/~ghost\/\">GhostScript<\/a>, <a href=\"http:\/\/www.cs.wisc.edu\/~ghost\/redmon\/\">RedMon<\/a>, and a Xerox DocuColor40 printer driver and rolled them into a <a href=\"http:\/\/nsis.sourceforge.net\/Main_Page\">simple NSIS install<\/a> to create a Distiller Knock-Off. I did have to write a small <a href=\"http:\/\/www.turboexplorer.com\/\">Win32 Delphi<\/a> application to do a little file management between RedMon and GhostScript but all it really does is shuffle files between the temp folder. I picked a DocuColor40 simply because I wanted the option to print to a 11x17 sheet of paper and I needed a PostScript driver.<\/p>\n<p>You can get it here: <a href=\"https:\/\/whiskeyandcode.com\/downloads\/Distiller-KO.exe\">Distiller-KO<\/a><\/p>","category":[{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/categories\/code\/","term":"Code","label":"Code"}},{"@attributes":{"scheme":"https:\/\/whiskeyandcode.com\/tags\/pdf\/","term":"Pdf","label":"Pdf"}}]}]}