<?xml version="1.0" encoding="utf-8"?><rss version="2.0"><channel><title>Musings Of An Idiot</title><link>http://www.edcourtenay.co.uk:80/musings-of-an-idiot</link><description>Musings Of An Idiot</description><item><title>NCrunch</title><link>http://www.edcourtenay.co.uk:80/musings-of-an-idiot/ncrunch</link><description>&lt;p&gt;A few months ago I was introduced by a colleague to a fantastic Visual Studio extension called &lt;a href="http://www.ncrunch.net/"&gt;NCrunch&lt;/a&gt;, and in a single stroke it has managed to almost completely change the way that I write, develop and maintain code (for the better).&lt;/p&gt; &lt;p&gt;NCrunch is an automatic continuous testing tool that, in the background, runs your unit tests against your code while you are developing. It adds a column of status indicators to your editor, which shows you three things:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Lines of code that are not covered by any unit tests  &lt;li&gt;Lines of code that are covered by unit tests where all unit tests pass  &lt;li&gt;Lines of code that are covered by unit tests where at least one test is failing&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;So, if I make a change to my code while I'm implementing a new business requirement or refactoring I get almost immediate feedback that my code has or hasn't adversely affected my other code paths (assuming that is that I've got appropriate unit test cases written for my code).&lt;/p&gt; &lt;p&gt;Which is the other great thing about NCrunch from my perspective - over time, the presence of a black dot to the left of your code that indicates that you've not got any unit test coverage for a particular code path starts to grate. In fact, whenever I've had to write code recently in projects that have no code coverage I've almost felt dirty - that little black dot keeps nagging me to drop what I'm doing and get some proper unit test coverage in place.&lt;/p&gt; &lt;p&gt;The ultimate accolade I can give NCrunch is that when I built a new development environment a few weeks ago, firing up Visual Studio without NCrunch (and &lt;a href="http://www.jetbrains.com/resharper/"&gt;ReSharper&lt;/a&gt; for that matter) felt unnatural and incomplete - a lot of extensions are 'nice to have', but this is now on my immediate install list.&lt;/p&gt; &lt;p&gt;NCrunch is still in beta at the moment and undergoing active development so there are sometimes some rough edges, but even given that it has been one of the most useful tools I've ever used.&lt;/p&gt;</description><pubDate>Mon, 06 Feb 2012 13:15:36 GMT</pubDate><guid isPermaLink="true">http://www.edcourtenay.co.uk:80/musings-of-an-idiot/ncrunch</guid></item><item><title>Calling MVC Areas From WebForm Pages</title><link>http://www.edcourtenay.co.uk:80/musings-of-an-idiot/2011/08/05/calling-mvc-areas-from-webform-pages</link><description>&lt;p&gt;I'm currently working on a project that involves moving a large classic ASP.NET WebForms application to ASP.NET MVC3; rather than completing re-implementing the system as MVC3 in one large hit, we're taking a hybrid approach so that existing WebForms content can run alongside the new MVC3 code.&lt;/p&gt;
&lt;p&gt;As part of this work, we realised we would need to be able to render content from ASP.NET MVC Areas from within WebForms pages, otherwise there would be a huge duplication of work involved in producing UserControls (or ServerControls) that duplicated the new functionality we are already writing as Areas. So, we started hunting around for a way to achieve this.&lt;/p&gt;
&lt;p&gt;After hunting around in MSDN and on StackOverflow, it turns out the solution is moderately easy; the first step is to create a dummy Controller:&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;public class WebFormController : Controller
{
}
&lt;/pre&gt;
&lt;p&gt;Seriously, that's all there is to it. Next, create a partial view that does nothing but render an Area:&lt;/p&gt;
&lt;pre class="brush: plain;"&gt;@Html.Action("Index", "Home", new { Area = "HelloWorld" })&lt;/pre&gt;
&lt;p&gt;Again, stupidly simple. The magic happens here though:&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;public class WebFormMvcUtil
{
    public static string RenderPartial(string partialName, object model)
    {
        var httpContextWrapper = new HttpContextWrapper(HttpContext.Current);

        var routeData = new RouteData();
        routeData.Values.Add("controller", "WebFormController");

        var controllerContext = new ControllerContext(new RequestContext(httpContextWrapper, routeData),
                                                      new WebFormController());

        IView view = ViewEngines.Engines.FindPartialView(controllerContext, partialName).View;

        ViewContext viewContext;
        var stringBuilder = new StringBuilder();
        using (var stringWriter = new StringWriter(stringBuilder))
        {
            viewContext = new ViewContext(controllerContext, view, new ViewDataDictionary {Model = model}, new TempDataDictionary(), stringWriter);
            view.Render(viewContext, viewContext.Writer);
        }

        return stringBuilder.ToString();
    }
}&lt;/pre&gt;
&lt;p&gt;With this in place I can now place a&lt;/p&gt;
&lt;pre class="brush: plain;"&gt;&amp;lt;%= WebFormMvcUtil.RenderPartial("_Area", null) %&amp;gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;directive in my WebForms page. So now, I have a mechanism to invoke a PartialView (and therefore, by extension, an Area) from our old codebase. Phew, crisis averted!&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description><pubDate>Fri, 05 Aug 2011 14:30:22 GMT</pubDate><guid isPermaLink="true">http://www.edcourtenay.co.uk:80/musings-of-an-idiot/2011/08/05/calling-mvc-areas-from-webform-pages</guid></item><item><title>Home Farm Festival 2011</title><link>http://www.edcourtenay.co.uk:80/musings-of-an-idiot/home-farm-festival-2011</link><description>&lt;p&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="Home Farm Festival" border="0" alt="home farm festival - supporting the piers simon appeal" src="http://www.pierssimonappeal.org/homefarmfest/images/homefarmfest_logo.png"&gt;&lt;/p&gt; &lt;p&gt;I’m chuffed to say that &lt;a href="http://www.cryinouloud.info/"&gt;Cryin’ Out Loud&lt;/a&gt; will be playing at the 6th &lt;a href="http://www.homefarmfestival.com/"&gt;Home Farm Festival&lt;/a&gt; in Chilthorne Domer on Saturday 11th June 2011; the full line up for the day is:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;The Helm&lt;/li&gt; &lt;li&gt;No Closure&lt;/li&gt; &lt;li&gt;Hundred Days&lt;/li&gt; &lt;li&gt;My Chloroform&lt;/li&gt; &lt;li&gt;Cryin’ Out Loud&lt;/li&gt; &lt;li&gt;Brought Into Being&lt;/li&gt; &lt;li&gt;Bleedin Hartz&lt;/li&gt; &lt;li&gt;Disciples&lt;/li&gt; &lt;li&gt;Shynah&lt;/li&gt; &lt;li&gt;The Little Unsaid&lt;/li&gt; &lt;li&gt;Nick Tatham&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Go &lt;a href="http://www.pierssimonappeal.org/homefarmfest/tickets.html"&gt;get your tickets people&lt;/a&gt;!&lt;/p&gt;</description><pubDate>Fri, 15 Apr 2011 14:15:40 GMT</pubDate><guid isPermaLink="true">http://www.edcourtenay.co.uk:80/musings-of-an-idiot/home-farm-festival-2011</guid></item><item><title>Wuthering Heights</title><link>http://www.edcourtenay.co.uk:80/musings-of-an-idiot/wuthering-heights</link><description>&lt;p&gt;A live version of Kate Bush’s classic Wuthering Heights by the &lt;a href="http://www.cryinoutloud.info"&gt;idiot bunch of loons&lt;/a&gt; that I sing with on a regular basis; this was recorded at The Royal Oak, Ilminster on June 4th 2010 after much beer had been consumed, so all duff notes and mistakes are – er – deliberate!&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:5737277B-5D6D-4f48-ABFC-DD9C333F4C5D:99f72506-b2d7-4c7a-bec7-597511f07002" class="wlWriterEditableSmartContent"&gt;&lt;div id="c76d5839-abf4-4493-9ce2-8870642ddff5" style="margin: 0px; padding: 0px; display: inline;"&gt;&lt;div&gt;&lt;a href="http://www.youtube.com/watch?v=oz7y9nRjgkk&amp;amp;feature=youtube_gdata_player" target="_new"&gt;&lt;img src="http://www.edcourtenay.co.uk/Media/Default/Windows-Live-Writer/d84e8da95fc8_ADED/video49ed59eeb4de.jpg" style="border-style: none" galleryimg="no" onload="var downlevelDiv = document.getElementById('c76d5839-abf4-4493-9ce2-8870642ddff5'); downlevelDiv.innerHTML = &amp;quot;&amp;lt;div&amp;gt;&amp;lt;object width=\&amp;quot;448\&amp;quot; height=\&amp;quot;252\&amp;quot;&amp;gt;&amp;lt;param name=\&amp;quot;movie\&amp;quot; value=\&amp;quot;http://www.youtube.com/v/oz7y9nRjgkk?hl=en&amp;amp;hd=1\&amp;quot;&amp;gt;&amp;lt;\/param&amp;gt;&amp;lt;embed src=\&amp;quot;http://www.youtube.com/v/oz7y9nRjgkk?hl=en&amp;amp;hd=1\&amp;quot; type=\&amp;quot;application/x-shockwave-flash\&amp;quot; width=\&amp;quot;448\&amp;quot; height=\&amp;quot;252\&amp;quot;&amp;gt;&amp;lt;\/embed&amp;gt;&amp;lt;\/object&amp;gt;&amp;lt;\/div&amp;gt;&amp;quot;;" alt=""&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description><pubDate>Wed, 13 Apr 2011 11:28:37 GMT</pubDate><guid isPermaLink="true">http://www.edcourtenay.co.uk:80/musings-of-an-idiot/wuthering-heights</guid></item><item><title>Autoloading Powershell Modules</title><link>http://www.edcourtenay.co.uk:80/musings-of-an-idiot/2011/04/13/autoloading-powershell-modules</link><description>&lt;p&gt;In a previous post I showed a &lt;a href="http://www.edcourtenay.co.uk/musings-of-an-idiot/validating-xml-documents-in-powershell"&gt;simple module to check the validity of XML documents&lt;/a&gt; from a Powershell command line. Over the past few months I’ve found this little function to be incredibly useful, enabling me to hunt down some odd errors that were being generated as part of our continuous integration builds and a few spurious errors in our live environments.&lt;/p&gt; &lt;p&gt;However, I was getting annoyed having to remember to import the module into my Powershell session every time I wanted to call the function – so I knocked together a simple autoloader script to handle this for me:&lt;/p&gt; &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:f32c3428-b7e9-4f15-a8ea-c502c7ff2e88:b8d495e2-2b4d-439d-8f85-5f664a8f21b0" class="wlWriterEditableSmartContent"&gt;&lt;pre class="brush: powershell;"&gt;function Autoload {
    $private:AutoLoad = @{
        Modules=@(
            'Xml-Utils',
            'Culture-Utils'
        );
        Paths=@(
            'C:\Cygwin\bin',
            'C:\Cygwin\usr\local\bin'
        );
    }

    foreach ($private:module in $AutoLoad.Modules) {
        Import-Module $module -EA SilentlyContinue
    }

    $private:arr = $env:path.Split(';') | Select -Unique
    foreach ($private:path in $private:AutoLoad.Paths) {
        if ($private:arr -notcontains $private:path) {
            $private:arr += $private:path
        }   
    }
    $env:path = [String]::Join(";", $private:arr)
}

#
# ...
#

Autoload
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;By changing the Modules array I can force Powershell to automatically load the modules I’m interested in with every console session. In reality, this array is stored as an XML document alongside my Microsoft.PowerShell_profile.ps1 file, but I’ll leave that as an exercise for the reader to implement. The second part of the function allows me to specify paths that I want to add to the environment path variable for each session.&lt;/p&gt;</description><pubDate>Wed, 13 Apr 2011 09:18:55 GMT</pubDate><guid isPermaLink="true">http://www.edcourtenay.co.uk:80/musings-of-an-idiot/2011/04/13/autoloading-powershell-modules</guid></item><item><title>Apologies</title><link>http://www.edcourtenay.co.uk:80/musings-of-an-idiot/2011/03/09/apologies</link><description>&lt;p&gt;Apologies for any duplications or reposting appearing in any RSS readers; I've made the last structural change to the site for a while, so hopefully the permalinks for any posts won't change (again)&lt;/p&gt;</description><pubDate>Wed, 09 Mar 2011 14:30:44 GMT</pubDate><guid isPermaLink="true">http://www.edcourtenay.co.uk:80/musings-of-an-idiot/2011/03/09/apologies</guid></item><item><title>Robots Failing In Orchard</title><link>http://www.edcourtenay.co.uk:80/musings-of-an-idiot/2011/03/08/OrchardRobots</link><description>&lt;p&gt;I've been getting to grips with the excellent &lt;a href="http://www.orchardproject.net/"&gt;ASP.Net Orchard&lt;/a&gt;, and have fully migrated my old blog over to this platform over the last couple of weeks - the issue that I had with the application restarting was due to my hosting provider having throttled the memory restrictions for my Application Pool too far. To their credit, once the issue was discovered they relaxed the restrictions immediately and the site has been working perfectly ever since.&lt;/p&gt;
&lt;p&gt;The only stupid little problem that I've had was with enabling Chad Sharf's &lt;a href="http://www.orchardproject.net/gallery/List/Modules/Orchard.Module.SH.Robots"&gt;Robots&lt;/a&gt; module which serves 'robots.txt' through the pipeline and provides a simple editor for it through the administration interface. Every time I tried to access 'robots.txt' from my site when the module was enabled I was being given a 404 error.&lt;/p&gt;
&lt;p&gt;After several hours pulling my hair out and trawling through the stupidly simple code, the answer hit me.&lt;/p&gt;
&lt;p&gt;When I'd originally set up Orchard before uploading to my hosting provider, I'd been using &lt;a href="http://www.microsoft.com/web/webmatrix/"&gt;WebMatrix&lt;/a&gt;; it turns out that WebMatrix had added a 'robots.txt' for me in the root of the project, which duly got copied over to my hosting provider when I deployed Orchard. This might not seem to be an issue, but Orchard's configuration explicitly turns off all handlers to force all requests through its own routing mechanism:&lt;/p&gt;
&lt;pre class="brush: xml"&gt;&amp;lt;handlers accessPolicy="Script"&amp;gt;
	&amp;lt;!-- clear all handlers, prevents executing code file extensions, prevents returning any file contents --&amp;gt;
	&amp;lt;clear/&amp;gt;
	&amp;lt;!-- Return 404 for all requests via managed handler. The url routing handler will substitute the mvc request handler when routes match. --&amp;gt;
	&amp;lt;add name="NotFound" path="*" verb="*" type="System.Web.HttpNotFoundHandler" preCondition="integratedMode" requireAccess="Script"/&amp;gt;
&amp;lt;/handlers&amp;gt;&lt;/pre&gt;
&lt;p&gt;The upshot if this meant that (counter-intuitively) if the 'robots.txt' file existed on the filesystem, any request for it would immediately return a 404 error and wouldn't hit the routing mechanism within Orchard - simply deleting the file immediately kicked the module into life.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description><pubDate>Tue, 08 Mar 2011 09:27:58 GMT</pubDate><guid isPermaLink="true">http://www.edcourtenay.co.uk:80/musings-of-an-idiot/2011/03/08/OrchardRobots</guid></item><item><title>Validating XML Documents In PowerShell</title><link>http://www.edcourtenay.co.uk:80/musings-of-an-idiot/validating-xml-documents-in-powershell</link><description>&lt;p&gt;I came across a problem the other day where a process that relied on several external XML documents was failing due to a combination of factors:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The document had been hand-edited&lt;/li&gt;
&lt;li&gt;The document contained UTF-8 characters&lt;/li&gt;
&lt;li&gt;The document had no encoding directive or BOM to identify it as containing UTF-8 characters&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So, I knocked together the following PowerShell module to validate XML documents from the command line:&lt;/p&gt;
&lt;pre class="brush: powershell"&gt;function Test-Xml {
    param([string[]]$Path)
    
    begin {
        $xml = new-object System.Xml.XmlDocument
        
        function TestXmlDocument([string]$path) {
            $relativePath = Resolve-Path $path -Relative
            Write-Host -NoNewLine "$relativePath : "
            
            trap [System.Xml.XmlException] { 
                $script:valid = $false
                $script:message = $_.Exception.Message
                continue; 
            }
            
            $script:valid = $true
            $resolvedPath = Resolve-Path $path
            $xml.Load($resolvedPath)
            
            if ($script:valid) {
                Write-Host -ForegroundColor Green "OK"
            } else {
                Write-Host -ForegroundColor Red "Failed - $script:message"
            }
        }
    }
    
    process {
        if ($_ -is [IO.FileInfo]) {
            TestXmlDocument $_.FullName
        } elseif ($_ -is [string]) {
            if (test-path -type Leaf $_) {
                TestXmlDocument $_
            }
        }
    }
    
    end {
        if ($Path) {
          foreach ($aPath in $Path) {
            TestXmlDocument $aPath
          }
        }
    }
}

Export-ModuleMember Test-Xml
&lt;/pre&gt;
&lt;p&gt;The function is implemented so that it can be invoked directly or as a filter. It can therefore be used to check a single file:&lt;/p&gt;
&lt;pre class="brush: powershell; ruler: false"&gt;Test-Xml fileToCheck.xml
&lt;/pre&gt;
&lt;p&gt;a list of files:&lt;/p&gt;
&lt;pre class="brush: powershell; ruler: false"&gt;Test-Xml file1.xml, file2.xml, file3.xml
&lt;/pre&gt;
&lt;p&gt;or against a set of files as part of a process:&lt;/p&gt;
&lt;pre class="brush: powershell; ruler: false"&gt;Get-ChildItems -Recurse -Include *.xml,*.config | Test-Xml&lt;/pre&gt;
&lt;p&gt;The code is probably not as clean as it could be, but it gets the job done.&lt;/p&gt;</description><pubDate>Wed, 02 Mar 2011 11:14:20 GMT</pubDate><guid isPermaLink="true">http://www.edcourtenay.co.uk:80/musings-of-an-idiot/validating-xml-documents-in-powershell</guid></item><item><title>Migrating To Orchard</title><link>http://www.edcourtenay.co.uk:80/musings-of-an-idiot/migrating-to-orchard</link><description>&lt;p&gt;It&amp;rsquo;s time to jump ship again and move to a new Blog system &amp;ndash; this time I&amp;rsquo;ve settled on &lt;a href="http://www.orchardproject.net/"&gt;Orchard&lt;/a&gt;, a .NET CMS system with (amongst other things) a full-featured blogging engine.&lt;/p&gt;
&lt;p&gt;Migrating from my previous system (&lt;a href="http://www.dasblog.info/"&gt;dasBlog&lt;/a&gt;) has been fairly straightforward, but not without its little challenges. I&amp;rsquo;ll detail the main steps I had to take in the hope that it will make life easier for anyone else attempting the same thing.&lt;/p&gt;
&lt;p&gt;Using &lt;a href="http://www.microsoft.com/web/webmatrix/"&gt;WebMatrix&lt;/a&gt; I set up a blank Orchard site on my local machine, and got the basic settings configured for the new site, leaving my existing site up and running on my hosting provider. From the Orchard Gallery link within Orchard itself, I downloaded and enabled the &lt;a href="http://orchardblogml.codeplex.com/"&gt;BlogML Module&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I then downloaded the &lt;a href="http://archive.msdn.microsoft.com/DasBlogML"&gt;&lt;span id="ctl00_ctl00_WideContent_ProjectTitleControl1_TitleLabel"&gt;DasBlog &amp;lt;-&amp;gt; BlogML&lt;/span&gt;&lt;/a&gt; utility and ran it against my local backup of my dasBlog site, generating a &lt;a href="http://blogml.org/"&gt;BlogML&lt;/a&gt; format export. I did an initial test-run importing the BlogML which worked fine, but I quickly hit an issue with all the images that I had embedded in my existing blog posts.&lt;/p&gt;
&lt;p&gt;Rather than editing all my existing posts and uploading new images for each one, I hacked together a small bit of code to grab assets from my existing site embed them in the BlogML export as Base64 encoded strings:&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;XDocument doc = XDocument.Load(@"blog.xml");
XNamespace ns = XNamespace.Get("http://www.blogml.com/2006/09/BlogML");

var posts = doc.Descendants(ns + "post");
var postsWithAttachments = posts.Where(p =&amp;gt; p.Descendants(ns + "attachment").Count() &amp;gt; 0);

foreach (var post in postsWithAttachments)
{
	foreach (var attachment in post.Descendants(ns + "attachment"))
	{
		WebClient client = new WebClient();
		var attribute = attachment.Attribute("external-uri").Value;

		Console.Write("{0}: ", attribute);

		byte[] data = null;
		try
		{
			data = client.DownloadData(attribute);
		}
		catch { }

		if (data != null)
		{
			Console.WriteLine("OK");
			attachment.SetAttributeValue("embedded", "true");
			attachment.SetValue(System.Convert.ToBase64String(data));
		}
		else
		{
			Console.WriteLine("Failed");
		}
	}
}

posts.Descendants(ns + "trackback").Cast&amp;lt;XNode&amp;gt;().ToList().ForEach(n =&amp;gt; n.Remove());
doc.Save(@"blog2.xml");
&lt;/pre&gt;
&lt;p&gt;As 99.9% of the trackback links in the export were from spam sites, I decided to simply drop them all from the export file. The BlogML plugin within Orchard handled the resulting BlogML file without a problem &amp;ndash; I know this is not in any way ideal, especially for very large sites, but it worked well for me; all the images were duly extracted and recreated in the appropriate Media folder.&lt;/p&gt;
&lt;p&gt;The only other issue was, I suspect, as a result of my hosting provider; Orchard would continually force me to log back in every 20 or so seconds once the site had been published up to the net. Adding a&lt;/p&gt;
&lt;pre class="brush: xml"&gt;&amp;lt;machinekey decryption="AES" validation="SHA1" decryptionkey="..." validationkey="..." /&amp;gt;
&lt;/pre&gt;
&lt;p&gt;directive to my web.config seemed to fix (or at least mask) the issue for the time being. There is a useful &lt;a href="http://aspnetresources.com/tools/machineKey"&gt;&amp;lt;machineKey&amp;gt; Generator&lt;/a&gt; available to get around the drudgery of having to generate the keys yourself.&lt;/p&gt;
&lt;p&gt;And that&amp;rsquo;s basically it; I&amp;rsquo;ve got a lot to learn about Orchard, and I&amp;rsquo;ve got a few ideas for some useful modules that I hope to bring online fairly soon.&lt;/p&gt;</description><pubDate>Mon, 28 Feb 2011 19:14:56 GMT</pubDate><guid isPermaLink="true">http://www.edcourtenay.co.uk:80/musings-of-an-idiot/migrating-to-orchard</guid></item><item><title>Generating 'Recently Added' Playlist with Powershell</title><link>http://www.edcourtenay.co.uk:80/musings-of-an-idiot/2010/06/23/GeneratingRecentlyAddedPlaylistWithPowershell</link><description>&lt;P&gt;A feature that I used to like in Windows Media Player 11 that was dropped in version 12 was the 'Recently Added' view. There is a &lt;A href="http://sawdustandglitter.com/2009/02/how-to-get-recently-added-back-in-windows-media-player-12-of-windows-7.html"&gt;way to produce an automatic playlist&lt;/A&gt; that includes recently added items, but it occurred to me that I use a variety of media players depending on my current whim (sometimes it'll even be a command line instance of mplayer through cygwin) and wouldn't it be great to have an auto-generated 'Recently Added' playlist in a format that any respectable media player would understand - namely &lt;A href="http://en.wikipedia.org/wiki/M3U"&gt;M3U&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;And besides, I wanted to play around with Powershell.&lt;/P&gt;
&lt;P&gt;So, I put together the following Powershell script; something that stumped me for a while was to do with resolving absolute paths to relative paths; my issue was:&lt;/P&gt;&lt;PRE&gt;&lt;SPAN style="BACKGROUND-COLOR: transparent; FONT-FAMILY: Courier New; COLOR: black; FONT-SIZE: 11px"&gt;resolve-path -relative &lt;SPAN style="BACKGROUND-COLOR: #e4e4e4; FONT-FAMILY: Courier New; COLOR: #666666; FONT-SIZE: 11px"&gt;"E:\Music\Autechre\Quaristice\01 Altibzz.mp3"&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;P&gt;would return&lt;/P&gt;&lt;PRE&gt;&lt;SPAN style="BACKGROUND-COLOR: transparent; FONT-FAMILY: Courier New; COLOR: black; FONT-SIZE: 11px"&gt;.\Autechre\Quaristice\01 Altibzz.mp3&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;P&gt;but&lt;/P&gt;&lt;PRE&gt;&lt;SPAN style="BACKGROUND-COLOR: transparent; FONT-FAMILY: Courier New; COLOR: black; FONT-SIZE: 11px"&gt;resolve-path -relative &lt;SPAN style="BACKGROUND-COLOR: #e4e4e4; FONT-FAMILY: Courier New; COLOR: #666666; FONT-SIZE: 11px"&gt;"E:\Music\Peter Gabriel\Hit Disc 2\14 Downside Up [Live].mp3"&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;P&gt;would return absolutely nothing. After returning to the script a few hours later, I realised that the issue was to do with wildcard expansion - Powershell uses '[...]' to match ranges or specified characters (see 'help wildcards' in Powershell). A quick flick through the help pages for resolve-path revealed a '-literalpath' parameter, which means that no wildcard expansion is performed. The following command therefore:&lt;/P&gt;&lt;PRE&gt;&lt;SPAN style="BACKGROUND-COLOR: transparent; FONT-FAMILY: Courier New; COLOR: black; FONT-SIZE: 11px"&gt;resolve-path -relative -literalpath &lt;SPAN style="BACKGROUND-COLOR: #e4e4e4; FONT-FAMILY: Courier New; COLOR: #666666; FONT-SIZE: 11px"&gt;"E:\Music\Peter Gabriel\Hit Disc 2\14 Downside Up [Live].mp3"&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;P&gt;gives&lt;/P&gt;&lt;PRE&gt;&lt;SPAN style="BACKGROUND-COLOR: transparent; FONT-FAMILY: Courier New; COLOR: black; FONT-SIZE: 11px"&gt;.\Peter Gabriel\Hit Disc 2\14 Downside Up [Live].mp3&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;P&gt;as expected.&lt;/P&gt;
&lt;P&gt;Just to round things off, I decided to emit extended M3U directives for applications that understand them. I stole the GetMP3MetaData function from &lt;A href="http://blogs.msdn.com/b/johan/archive/2008/09/23/powershell-automatically-organizing-your-mp3-collection.aspx"&gt;Johan Straarup's blog entry&lt;/A&gt; which uses an interesting trick by instantiating a Shell.Application COM object and accessing the properties that it exposes on a selected file. From this information I could write out the relevant tag information from the selected files and calculate the length of the file in seconds.&lt;/P&gt;
&lt;P&gt;From the Powershell command line, you can run the script as&lt;/P&gt;&lt;PRE&gt;&lt;SPAN style="BACKGROUND-COLOR: transparent; FONT-FAMILY: Courier New; COLOR: black; FONT-SIZE: 11px"&gt;.\Recently-Added.ps1 &lt;SPAN style="BACKGROUND-COLOR: transparent; FONT-FAMILY: Courier New; COLOR: red; FONT-SIZE: 11px"&gt;|&lt;/SPAN&gt; Set-Content &lt;SPAN style="BACKGROUND-COLOR: #e4e4e4; FONT-FAMILY: Courier New; COLOR: #666666; FONT-SIZE: 11px"&gt;"Recently Added.m3u"&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;P&gt;By default, it will produce a playlist of MP3 files that were created within the last 14 days; this can be adjusted by specifying the '-Days' parameter. For example, to create a list containing files created within the last 21 days:&lt;/P&gt;&lt;PRE&gt;&lt;SPAN style="BACKGROUND-COLOR: transparent; FONT-FAMILY: Courier New; COLOR: black; FONT-SIZE: 11px"&gt;.\Recently-Added.ps1 -Days 21&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;P&gt;I hope someone finds this useful someday.&lt;/P&gt;&lt;PRE&gt;&lt;SPAN style="BACKGROUND-COLOR: transparent; FONT-FAMILY: Courier New; COLOR: black; FONT-SIZE: 11px"&gt;#
# Recently-Added.ps1
#
param([&lt;SPAN style="BACKGROUND-COLOR: transparent; FONT-FAMILY: Courier New; COLOR: blue; FONT-SIZE: 11px"&gt;int&lt;/SPAN&gt;]$Days &lt;SPAN style="BACKGROUND-COLOR: transparent; FONT-FAMILY: Courier New; COLOR: red; FONT-SIZE: 11px"&gt;=&lt;/SPAN&gt; 14)
$objShell &lt;SPAN style="BACKGROUND-COLOR: transparent; FONT-FAMILY: Courier New; COLOR: red; FONT-SIZE: 11px"&gt;=&lt;/SPAN&gt; New-Object -ComObject Shell.Application

function GetMP3MetaData($path)
{
    $file &lt;SPAN style="BACKGROUND-COLOR: transparent; FONT-FAMILY: Courier New; COLOR: red; FONT-SIZE: 11px"&gt;=&lt;/SPAN&gt; split-path $path -leaf
    $path &lt;SPAN style="BACKGROUND-COLOR: transparent; FONT-FAMILY: Courier New; COLOR: red; FONT-SIZE: 11px"&gt;=&lt;/SPAN&gt; split-path $path
    $objFolder &lt;SPAN style="BACKGROUND-COLOR: transparent; FONT-FAMILY: Courier New; COLOR: red; FONT-SIZE: 11px"&gt;=&lt;/SPAN&gt; $objShell.&lt;SPAN style="BACKGROUND-COLOR: transparent; FONT-FAMILY: Courier New; FONT-SIZE: 11px"&gt;namespace&lt;/SPAN&gt;($path)
    $objFile &lt;SPAN style="BACKGROUND-COLOR: transparent; FONT-FAMILY: Courier New; COLOR: red; FONT-SIZE: 11px"&gt;=&lt;/SPAN&gt; $objFolder.parsename($file)
    $result &lt;SPAN style="BACKGROUND-COLOR: transparent; FONT-FAMILY: Courier New; COLOR: red; FONT-SIZE: 11px"&gt;=&lt;/SPAN&gt; @{}
    0..266 &lt;SPAN style="BACKGROUND-COLOR: transparent; FONT-FAMILY: Courier New; COLOR: red; FONT-SIZE: 11px"&gt;|&lt;/SPAN&gt; &lt;SPAN style="BACKGROUND-COLOR: transparent; FONT-FAMILY: Courier New; COLOR: red; FONT-SIZE: 11px"&gt;%&lt;/SPAN&gt; {
        &lt;SPAN style="BACKGROUND-COLOR: transparent; FONT-FAMILY: Courier New; COLOR: blue; FONT-SIZE: 11px"&gt;if&lt;/SPAN&gt; ($objFolder.getDetailsOf($objFile, $_)) {
            $result[$($objFolder.getDetailsOf($objFolder.items, $_))] &lt;SPAN style="BACKGROUND-COLOR: transparent; FONT-FAMILY: Courier New; COLOR: red; FONT-SIZE: 11px"&gt;=&lt;/SPAN&gt; $objFolder.getDetailsOf($objFile, $_)
        }
    }
    &lt;SPAN style="BACKGROUND-COLOR: transparent; FONT-FAMILY: Courier New; COLOR: blue; FONT-SIZE: 11px"&gt;return&lt;/SPAN&gt; $result
}

&lt;SPAN style="BACKGROUND-COLOR: #e4e4e4; FONT-FAMILY: Courier New; COLOR: #666666; FONT-SIZE: 11px"&gt;"#EXTM3U"&lt;/SPAN&gt;
gci -recurse -include *.mp3 &lt;SPAN style="BACKGROUND-COLOR: transparent; FONT-FAMILY: Courier New; COLOR: red; FONT-SIZE: 11px"&gt;|&lt;/SPAN&gt; `
    ? { $_.CreationTime -gt (get-date).AddDays($Days &lt;SPAN style="BACKGROUND-COLOR: transparent; FONT-FAMILY: Courier New; COLOR: red; FONT-SIZE: 11px"&gt;*&lt;/SPAN&gt; -1) } &lt;SPAN style="BACKGROUND-COLOR: transparent; FONT-FAMILY: Courier New; COLOR: red; FONT-SIZE: 11px"&gt;|&lt;/SPAN&gt; `
    &lt;SPAN style="BACKGROUND-COLOR: transparent; FONT-FAMILY: Courier New; COLOR: red; FONT-SIZE: 11px"&gt;%&lt;/SPAN&gt; {
        $path &lt;SPAN style="BACKGROUND-COLOR: transparent; FONT-FAMILY: Courier New; COLOR: red; FONT-SIZE: 11px"&gt;=&lt;/SPAN&gt; resolve-path -relative -literalpath $_.FullName
        $info &lt;SPAN style="BACKGROUND-COLOR: transparent; FONT-FAMILY: Courier New; COLOR: red; FONT-SIZE: 11px"&gt;=&lt;/SPAN&gt; GetMP3MetaData($_)
        $duration &lt;SPAN style="BACKGROUND-COLOR: transparent; FONT-FAMILY: Courier New; COLOR: red; FONT-SIZE: 11px"&gt;=&lt;/SPAN&gt; [timespan]$info.Duration
        &lt;SPAN style="BACKGROUND-COLOR: #e4e4e4; FONT-FAMILY: Courier New; COLOR: #666666; FONT-SIZE: 11px"&gt;"#EXTINF:{0},{1} - {2}"&lt;/SPAN&gt; -f $duration.TotalSeconds, $info.Artist, $info.Title
        $path
    }
&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description><pubDate>Wed, 23 Jun 2010 11:15:05 GMT</pubDate><guid isPermaLink="true">http://www.edcourtenay.co.uk:80/musings-of-an-idiot/2010/06/23/GeneratingRecentlyAddedPlaylistWithPowershell</guid></item><item><title>The Story of Little Suck-a-Thumb</title><link>http://www.edcourtenay.co.uk:80/musings-of-an-idiot/2009/08/05/TheStoryOfLittleSuckaThumb</link><description>&lt;p&gt;One of the highlights of going to visit my Amma as a small boy used to be reading the old hardback copy of &amp;quot;&lt;a href="http://en.wikipedia.org/wiki/Struwwelpeter" target="_blank"&gt;Struwwelpeter: Merry Tales and Funny Pictures&lt;/a&gt;&amp;quot; by Heinrich Hoffman – although it was the inspiration for several recurring nightmares, there was something grotesquely compelling about the book that meant I couldn’t stop re-reading it. The idea that any of the stories could have been described as &amp;quot;Merry Tales&amp;quot; or that this could in any way be considered a children's book was (and still is) bizarre.&lt;/p&gt;  &lt;p&gt;My favourite story was always &amp;quot;The Story Of Little Suck-a-Thumb&amp;quot;; it’s the completely cold and matter of fact way in which the unfortunate boy’s mother reacts to her son's mutilation at the hands of the tailor and the freakish illustration of the &amp;quot;great, long, red-legged scissor-man&amp;quot; himself leaping in through the open door with his enormous shears that completely captivated me then (and now).&lt;/p&gt;  &lt;div align="center"&gt;   &lt;h5&gt;&lt;a&gt;&lt;/a&gt;The Story of Little Suck-a-Thumb&lt;/h5&gt;    &lt;p&gt;&lt;img title="The Story of Little Suck-A-Thumb" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="901" alt="The Story of Little Suck-A-Thumb" src="/Media/Default/Attachments/017_3.jpg" width="404" border="0" /&gt;&lt;/p&gt;    &lt;p&gt;&lt;em&gt;One day Mamma said &amp;quot;Conrad dear,        &lt;br /&gt;I must go out and leave you here.         &lt;br /&gt;But mind now, Conrad, what I say,         &lt;br /&gt;Don't suck your thumb while I'm away.         &lt;br /&gt;The great tall tailor always comes         &lt;br /&gt;To little boys who suck their thumbs;         &lt;br /&gt;And ere they dream what he's about,         &lt;br /&gt;He takes his great sharp scissors out,         &lt;br /&gt;And cuts their thumbs clean off—and then,         &lt;br /&gt;You know, they never grow again.&amp;quot;         &lt;br /&gt;Mamma had scarcely turned her back,         &lt;br /&gt;The thumb was in, Alack! Alack!&lt;/em&gt;&lt;/p&gt;    &lt;p&gt;&lt;img title="The great, long, red-legged scissor-man." style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="404" alt="The great, long, red-legged scissor-man." src="/Media/Default/Attachments/018-1_3.jpg" width="604" border="0" /&gt; &lt;/p&gt;    &lt;p&gt;&lt;em&gt;The door flew open, in he ran,        &lt;br /&gt;The great, long, red-legged scissor-man.         &lt;br /&gt;Oh! children, see! the tailor's come         &lt;br /&gt;And caught out little Suck-a-Thumb.         &lt;br /&gt;Snip! Snap! Snip! the scissors go;         &lt;br /&gt;And Conrad cries out &amp;quot;Oh! Oh! Oh!&amp;quot;         &lt;br /&gt;Snip! Snap! Snip! They go so fast,         &lt;br /&gt;That both his thumbs are off at last.&lt;/em&gt;&lt;/p&gt;    &lt;p&gt;&amp;#160; &lt;br /&gt;&lt;img title="Mamma comes home, there Conrad stands" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="456" alt="Mamma comes home, there Conrad stands" src="/Media/Default/Attachments/018-2_3.jpg" width="351" border="0" /&gt; &lt;/p&gt;    &lt;p&gt;&lt;em&gt;Mamma comes home: there Conrad stands,        &lt;br /&gt;And looks quite sad, and shows his hands;         &lt;br /&gt;&amp;quot;Ah!&amp;quot; said Mamma, &amp;quot;I knew he'd come         &lt;br /&gt;To naughty little Suck-a-Thumb.&amp;quot;&lt;/em&gt;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;The complete nightmare can be downloaded from &lt;a href="http://www.gutenberg.org/etext/12116" target="_blank"&gt;Project Gutenberg&lt;/a&gt;&lt;/p&gt;</description><pubDate>Wed, 05 Aug 2009 09:25:32 GMT</pubDate><guid isPermaLink="true">http://www.edcourtenay.co.uk:80/musings-of-an-idiot/2009/08/05/TheStoryOfLittleSuckaThumb</guid></item><item><title>Custom DS Lite</title><link>http://www.edcourtenay.co.uk:80/musings-of-an-idiot/2009/07/23/CustomDSLite</link><description>&lt;p&gt;The hinge on India’s pink DS lite broke the other day, which left the top screen hanging on precariously for dear life, so rather than risk the wrath of an eight year old if the thing did give out I got a replacement case. I opted for a nice purple colour and armed with a trusty triwing screwdriver, miniature screwdriver set and a couple of young helpers I replaced the case.&lt;/p&gt;  &lt;p&gt;I opted to keep the original pink DS’s buttons, D-pad and screen decals – I think the end result is quite fetching.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.edcourtenay.co.uk/content/binary/WindowsLiveWriter/CustomDSLite_10272/23072009002-edit_2.jpg"&gt;&lt;img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="Pink n&amp;#39; Purple DS" border="0" alt="Pink n&amp;#39; Purple DS" src="/Media/Default/Attachments/23072009002-edit_thumb.jpg" width="644" height="484" /&gt;&lt;/a&gt;&lt;/p&gt;</description><pubDate>Thu, 23 Jul 2009 17:22:38 GMT</pubDate><guid isPermaLink="true">http://www.edcourtenay.co.uk:80/musings-of-an-idiot/2009/07/23/CustomDSLite</guid></item><item><title>Amusing Ourselves To Death</title><link>http://www.edcourtenay.co.uk:80/musings-of-an-idiot/2009/07/17/AmusingOurselvesToDeath</link><description>&lt;p&gt;Just stumbled across this cartoon via B3ta; it makes the case that Aldous Huxley was the more prophetic author compared to George Orwell, contrasting Brave New World against 1984. It’s true that Orwell may have enriched the English language more than Huxley (Newspeak, Big Brother, Room 101, Doublethink etc.), but Huxley may well have had the more accurate vision.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://fatpita.net/?i=1952"&gt;&lt;img src="http://fatpita.net/images/image%20(1952).jpg" width="699" height="5579" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://fatpita.net/?i=1952"&gt;http://fatpita.net/?i=1952&lt;/a&gt;&lt;/p&gt;</description><pubDate>Fri, 17 Jul 2009 19:06:31 GMT</pubDate><guid isPermaLink="true">http://www.edcourtenay.co.uk:80/musings-of-an-idiot/2009/07/17/AmusingOurselvesToDeath</guid></item><item><title>Gig Cancelled</title><link>http://www.edcourtenay.co.uk:80/musings-of-an-idiot/2009/06/18/GigCancelled</link><description>The gig tonight at The Old Ship in Dorcester is not happening – cock up with booking confirmations!</description><pubDate>Thu, 18 Jun 2009 12:37:04 GMT</pubDate><guid isPermaLink="true">http://www.edcourtenay.co.uk:80/musings-of-an-idiot/2009/06/18/GigCancelled</guid></item><item><title>Parmageddon - The origin</title><link>http://www.edcourtenay.co.uk:80/musings-of-an-idiot/2009/04/30/ParmageddonTheOrigin</link><description>

&lt;div class=Section1&gt;

&lt;div&gt;

&lt;p class=MsoNormal&gt;The source of the aporkalypse has been identified....&lt;o:p&gt;&lt;/o:p&gt;&lt;/p&gt;

&lt;div&gt;

&lt;p class=MsoNormal&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/p&gt;

&lt;/div&gt;

&lt;/div&gt;

&lt;/div&gt;

&lt;div class="inlinedMailPictureBox"&gt;&lt;a href="/Media/Default/Attachments/swine.jpg"&gt;&lt;img border="0" class="inlinedMailPicture" src="/Media/Default/Attachments/swine-thumb.dasblog.JPG"&gt;&lt;/a&gt;&lt;br&gt;&lt;a class="inlinedMailPictureLink" href="/Media/Default/Attachments/swine.jpg"&gt;swine.jpg&lt;/a&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;</description><pubDate>Thu, 30 Apr 2009 20:16:04 GMT</pubDate><guid isPermaLink="true">http://www.edcourtenay.co.uk:80/musings-of-an-idiot/2009/04/30/ParmageddonTheOrigin</guid></item><item><title>Shirley Temple Pilots Not Dead Shocker</title><link>http://www.edcourtenay.co.uk:80/musings-of-an-idiot/2009/04/07/ShirleyTemplePilotsNotDeadShocker</link><description>Yes, it's true; the Shirley Temple Pilots are going to be playing for the
first time in ages at Finns in Weymouth on Sat 11th July. It'll be loud....
;)

</description><pubDate>Tue, 07 Apr 2009 22:12:12 GMT</pubDate><guid isPermaLink="true">http://www.edcourtenay.co.uk:80/musings-of-an-idiot/2009/04/07/ShirleyTemplePilotsNotDeadShocker</guid></item><item><title>ASP.NET MVC 1.0</title><link>http://www.edcourtenay.co.uk:80/musings-of-an-idiot/2009/04/03/ASPNETMVC10</link><description>&lt;p&gt;Are Microsoft really starting to turn a page when it comes to Open Source? Let’s hope so; they’ve just released the source code to the (excellent) &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=53289097-73ce-43bf-b6a6-35e00103cb4b&amp;amp;displaylang=en"&gt;ASP.NET MVC&lt;/a&gt; framework under the &lt;a href="http://www.opensource.org/licenses/ms-pl.html"&gt;OSI-approved MS-PL license&lt;/a&gt;. There's more &lt;a href="http://weblogs.asp.net/scottgu/archive/2009/04/01/asp-net-mvc-1-0.aspx"&gt;information over at Scott Guthrie’s blog&lt;/a&gt; – I’d particularly recommend reading his &lt;a href="http://weblogs.asp.net/scottgu/archive/2009/03/10/free-asp-net-mvc-ebook-tutorial.aspx"&gt;ASP.NET MVC PDF tutorial&lt;/a&gt; as it gives an excellent overview of ASP.NET MVC itself.&lt;/p&gt;</description><pubDate>Fri, 03 Apr 2009 07:11:17 GMT</pubDate><guid isPermaLink="true">http://www.edcourtenay.co.uk:80/musings-of-an-idiot/2009/04/03/ASPNETMVC10</guid></item><item><title>Fake Java enums using C# extension methods</title><link>http://www.edcourtenay.co.uk:80/musings-of-an-idiot/2009/03/25/FakeJavaEnumsUsingCExtensionMethods</link><description>&lt;p&gt;One of the nice features introduced into Java 1.5 that is missing in C# is enum types. In C#, enums are nothing more than a defined set of values with labels, whereas in Java enums can contain methods. I've seen a few attempts to mimic Java enums in C#, but most solutions seem to rely on Attributes to decorate the enum which is fine except that in relative terms, reflection operations are expensive.&lt;/p&gt;
&lt;p&gt;C# 3.0 introduced the concept of &lt;a href="http://msdn.microsoft.com/en-us/library/bb383977.aspx"&gt;extension methods&lt;/a&gt; which enable you to "add" methods to existing types without creating a new derived type, recompiling, or otherwise modifying the original type. As is my wont, I was thinking about this in the shower this morning when I had a eureka moment - surely it should be possible to fake Java enums using C# extension methods?&lt;/p&gt;
&lt;p&gt;Using the &lt;a href="http://java.sun.com/j2se/1.5.0/docs/guide/language/enums.html"&gt;Java planets example&lt;/a&gt;, it didn't take long to whip up the following:&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;using System;
using System.Collections.Generic;

namespace ScratchPad
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            var p = new Program();
            p.Run();
        }

        private void Run()
        {
            double earthWeight = 175;
            double mass = earthWeight / Planet.Earth.SurfaceGravity();

            foreach (Planet planet in Enum.GetValues(typeof(Planet))) {
                Console.WriteLine("Your weight on {0} is {1}", planet, planet.SurfaceWeight(mass));
            }
        }
    }

    public enum Planet
    {
        Mercury,
        Venus,
        Earth,
        Mars,
        Jupiter,
        Saturn,
        Uranus,
        Neptune
    }

    public static class PlanetExtensions
    {
        private static readonly Dictionary planetMap = new Dictionary
          {
              {Planet.Mercury, new PlanetData(3.303e+23, 2.4397e6)},
              {Planet.Venus, new PlanetData(4.869e+24, 6.0518e6)},
              {Planet.Earth, new PlanetData(5.976e+24, 6.37814e6)},
              {Planet.Mars, new PlanetData(6.421e+23, 3.3972e6)},
              {Planet.Jupiter, new PlanetData(1.9e+27,   7.1492e7)},
              {Planet.Saturn, new PlanetData(5.688e+26, 6.0268e7)},
              {Planet.Uranus, new PlanetData(8.686e+25, 2.5559e7)},
              {Planet.Neptune, new PlanetData(1.024e+26, 2.4746e7)}
          };

        private const double G = 6.67300E-11;

        public static double Mass(this Planet planet)
        {
            return GetPlanetData(planet).Mass;
        }

        public static double Radius(this Planet planet)
        {
            return GetPlanetData(planet).Radius;
        }

        public static double SurfaceGravity(this Planet planet)
        {
            PlanetData planetData = GetPlanetData(planet);

            return G * planetData.Mass / (planetData.Radius * planetData.Radius);
        }

        public static double SurfaceWeight(this Planet planet, double mass)
        {
            return mass * SurfaceGravity(planet);
        }

        private static PlanetData GetPlanetData(Planet planet)
        {
            if (!planetMap.ContainsKey(planet))
                throw new ArgumentOutOfRangeException("planet", "Unknown Planet");

            return planetMap[planet];
        }

        #region Nested type: PlanetData

        public class PlanetData
        {            
            public PlanetData(double mass, double radius)
            {
                Mass = mass;
                Radius = radius;
            }

            public double Mass { get; private set; }
            public double Radius { get; private set; }
        }

        #endregion
    }
}
&lt;/pre&gt;
&lt;p&gt;It's all very simple; the only drawback is that you must remember to match any changes to your enum in the associated extension class. Overall, I think this is a pattern I might start to use more often.&lt;/p&gt;</description><pubDate>Wed, 25 Mar 2009 10:23:36 GMT</pubDate><guid isPermaLink="true">http://www.edcourtenay.co.uk:80/musings-of-an-idiot/2009/03/25/FakeJavaEnumsUsingCExtensionMethods</guid></item><item><title>Missing</title><link>http://www.edcourtenay.co.uk:80/musings-of-an-idiot/2009/03/13/Missing</link><description>&lt;p&gt;It’s funny how little things can really get under your skin and annoy you; at work, I use a combination of Windows XP and Windows 2003 Server for development and day to day work which is fine, but as I use Vista at home I find that I miss the UI enhancements more and more.&lt;/p&gt;  &lt;p&gt;Unlike a lot of people, I seem to have had a rosy experience with Vista; maybe because I didn’t have unrealistic expectations about the OS (I wouldn’t dream of running it on some of the older machines I’ve seen it shoehorned into), and I’ve had some reasonably up to date hardware to run it on. The only real issues that I had with the OS were very early in its life, when some of the third-party drivers for my hardware devices were less than stable – my Hauppauge TV capture card was a prime example. Nowadays though I struggle to find any such issues, even though I’m running the x64 version of Vista.&lt;/p&gt;  &lt;p&gt;My particular bugbear at the moment is the XP (and Windows 2003) Start Menu; I’ve got so used to the convenience of the Search function in Vista that not having it available is like having an arm tied behind my back. The amount of times I find myself instinctively pressing the Windows key and then typing “Visual” to find Visual Studio on my development box is ridiculous.&lt;/p&gt;  &lt;p&gt;What’s even more annoying is that my work laptop was originally purchased with Vista, which was when downgraded to XP by the IT department...&lt;/p&gt;</description><pubDate>Fri, 13 Mar 2009 12:20:24 GMT</pubDate><guid isPermaLink="true">http://www.edcourtenay.co.uk:80/musings-of-an-idiot/2009/03/13/Missing</guid></item><item><title>Tree Power</title><link>http://www.edcourtenay.co.uk:80/musings-of-an-idiot/2009/02/22/TreePower</link><description>&lt;div align="center"&gt;&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/65Chy5kPQ-Y&amp;amp;color1=0xb1b1b1&amp;amp;color2=0xcfcfcf&amp;amp;feature=player_embedded&amp;amp;fs=1"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/65Chy5kPQ-Y&amp;amp;color1=0xb1b1b1&amp;amp;color2=0xcfcfcf&amp;amp;feature=player_embedded&amp;amp;fs=1" type="application/x-shockwave-flash" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/div&gt;  &lt;p&gt;Came across this video via &lt;a href="http://www.b3ta.com"&gt;B3ta&lt;/a&gt; – very clever.&lt;/p&gt;</description><pubDate>Sun, 22 Feb 2009 15:50:36 GMT</pubDate><guid isPermaLink="true">http://www.edcourtenay.co.uk:80/musings-of-an-idiot/2009/02/22/TreePower</guid></item></channel></rss>
