<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feed.damieng.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" version="2.0">

<channel>
	<title>DamienG</title>
	
	<link>http://damieng.com</link>
	<description>A .NET developer in Redmond</description>
	<lastBuildDate>Fri, 09 Jul 2010 14:19:33 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feed.damieng.com/DamienG" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="damieng" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://add.my.yahoo.com/rss?url=http%3A%2F%2Ffeed.damieng.com%2FDamienG" src="http://us.i1.yimg.com/us.yimg.com/i/us/my/addtomyyahoo4.gif">Subscribe with My Yahoo!</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.newsgator.com/ngs/subscriber/subext.aspx?url=http%3A%2F%2Ffeed.damieng.com%2FDamienG" src="http://www.newsgator.com/images/ngsub1.gif">Subscribe with NewsGator</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://feeds.my.aol.com/add.jsp?url=http%3A%2F%2Ffeed.damieng.com%2FDamienG" src="http://o.aolcdn.com/favorites.my.aol.com/webmaster/ffclient/webroot/locale/en-US/images/myAOLButtonSmall.gif">Subscribe with My AOL</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.bloglines.com/sub/http://feed.damieng.com/DamienG" src="http://www.bloglines.com/images/sub_modern11.gif">Subscribe with Bloglines</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.netvibes.com/subscribe.php?url=http%3A%2F%2Ffeed.damieng.com%2FDamienG" src="http://www.netvibes.com/img/add2netvibes.gif">Subscribe with Netvibes</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://fusion.google.com/add?feedurl=http%3A%2F%2Ffeed.damieng.com%2FDamienG" src="http://buttons.googlesyndication.com/fusion/add.gif">Subscribe with Google</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.pageflakes.com/subscribe.aspx?url=http%3A%2F%2Ffeed.damieng.com%2FDamienG" src="http://www.pageflakes.com/ImageFile.ashx?instanceId=Static_4&amp;fileName=ATP_blu_91x17.gif">Subscribe with Pageflakes</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.live.com/?add=http%3A%2F%2Ffeed.damieng.com%2FDamienG" src="http://tkfiles.storage.msn.com/x1piYkpqHC_35nIp1gLE68-wvzLZO8iXl_JMledmJQXP-XTBOLfmQv4zhj4MhcWEJh_GtoBIiAl1Mjh-ndp9k47If7hTaFno0mxW9_i3p_5qQw">Subscribe with Live.com</feedburner:feedFlare><item>
		<title>Anatomy of a good bug report</title>
		<link>http://damieng.com/blog/2010/06/30/anatomy-of-a-good-bug-report?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=anatomy-of-a-good-bug-report</link>
		<comments>http://damieng.com/blog/2010/06/30/anatomy-of-a-good-bug-report#comments</comments>
		<pubDate>Wed, 30 Jun 2010 19:57:45 +0000</pubDate>
		<dc:creator>Damien Guard</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[bug report]]></category>
		<category><![CDATA[bugs]]></category>

		<guid isPermaLink="false">http://damieng.com/?p=1644</guid>
		<description>Working on the .NET Framework was an interesting but often difficult time especially when dealing with vague or incomprehensible bug reports. Look before you file Head to Bing, Google, official support sites and bug database if you have access to it (Microsoft Connect, Apple Radar, Bugzilla for Firefox etc.) to see if others have run [...]</description>
			<content:encoded><![CDATA[<p>Working on the .NET Framework was an interesting but often difficult time especially when dealing with vague or incomprehensible bug reports.</p>
<h3>Look before you file</h3>
<p>Head to Bing, Google, official support sites and bug database if you have access to it (<a href="http://connect.microsoft.com/">Microsoft Connect</a>, <a href="http://radar.apple.com">Apple Radar</a>, <a href="https://bugzilla.mozilla.org/">Bugzilla for Firefox</a> etc.) to see if others have run into this issue. Searching for the error message can yield good results but remove any elements of the message specific to your project (e.g. class names, property names etc.)</p>
<div class="aside" style="float: right; width: 30%;">
<h4 id="why-workaround">Why accept a workaround?</h4>
<p>Do not underestimate the value of a solid workaround.</p>
<p>A patch is significant effort for both sides and for re-distributable components like .NET Framework getting the components to the right place can be tough. You&#8217;ll need to deploy to your team, build, test and staging environments and, if you distribute software, to all your customers.</p>
<p>This can be especially painful when strictly controlled environments are shared with others and ops teams are hesitant about putting patches or hotfixes into production. Factor in processor architectures, operating systems and language support and weigh it up.</p>
</div>
<p>The reasons for this are:</p>
<ul>
<li>you may have made a mistake (likely if the software has seen considerable use)</li>
<li>behave differently to your expectations (the dreaded &#8216;by design&#8217;)</li>
<li>already be fixed (in the next release and possibly as a patch)</li>
<li>have an acceptable workaround (<a href="#why-workaround">why accept a workaround?</a>)</li>
</ul>
<p>If you are running into problems with developer tools also check out:</p>
<ul>
<li>Official forums (<a href="http://social.msdn.microsoft.com/Forums/">MSDN Forums</a> &amp; <a href="http://forums.asp.net/">ASP.NET Forums</a> for Microsoft tools)</li>
<li>Unofficial respected sites (<a href="http://stackoverflow.com">StackOverflow</a>)</li>
</ul>
<p>Consider how likely it is you&#8217;ve discovered a bug given the complexity of what you are doing, how unusual it is and how mature the software is. Attempting something simple on an established piece of software likely means you&#8217;ve made a mistake or misunderstood the documentation.</p>
<h3>A good bug report</h3>
<p>So you decided to go ahead and report the bug (we all want better software after all).</p>
<p>The essence of a good bug report is having just the right amount of information to identify the bug without any unnecessary detail.</p>
<p>Let&#8217;s break it down.</p>
<h3>What happened</h3>
<p>The most important element is describing what happened and there are four major possibilities.</p>
<h4>Error message</h4>
<p>You told the software to do something and it displayed an error message instead.</p>
<p>On a good day the error message lets you know why it can&#8217;t do what you asked and lets you know what to do to make it work. Given you&#8217;re filing a bug report it isn&#8217;t one of those days.</p>
<p>The error message is likely cryptic, doesn&#8217;t tell you how to get what you want or is just plain wrong. We&#8217;ll need that message in its entirety so:</p>
<ul class="information">
<li>Copy Windows message box contents as text by pressing control-c when it&#8217;s in focus</li>
<li>When there is a lot of text take a screen print (printscreen on Windows, command-shift-3 on Mac OS X)</li>
<li>Localized error messages may slow down support responses &#8211; switch the app back to their language first</li>
</ul>
<h4>Exceptions</h4>
<p>When a piece of a program (called a method or function) can&#8217;t do what it claims it throws an &#8216;exception&#8217; back up to the piece that asked (called) it. This exception is like an error message but with enough lot of technical detail that travels back up the program until something deals with it (known as a catch).</p>
<p>When you see an exception then nothing wanted to deal with it.</p>
<p>You will see an error message that contains the exception and possibly a list of program pieces that couldn&#8217;t deal with it. This is called a stack trace and is invaluable to the person investigating your report so include it.</p>
<p>Developers seeing exceptions in their own program need to determine if they should be catching that exception or whether it shouldn&#8217;t be occurring. Feel frim the stack trace so your own methods aren&#8217;t included but too much is better than too little.</p>
<h4>Unexpected behaviour</h4>
<p>The software should have done what you wanted but did something you didn&#8217;t expect instead.</p>
<p>Report what you thought should happen, what the software did instead, how this is different and the reason why you think it should be that way.</p>
<p>Other people may not agree with your change and in the case of shared programming libraries or frameworks a fix for you can become a break for others that rely on existing behaviour.</p>
<h4>Terminated</h4>
<p>The software just vanished from the screen without a trace. Crashed, terminated or unexpectedly quit and perhaps took some of your work with it :(</p>
<p>If you&#8217;re really unlucky the software that crashed is your operating system. The blue screen of death (BSOD) on Windows, the grey screen on Mac OS X.</p>
<p>Often there are logs left behind you can examine to identify what went wrong.</p>
<p>On Mac OS X fire up <em>Console </em>from <em>Application &gt; Utilities</em> and see what you can find. iPhones, iPods and iPads do this quite often and iTunes will likely offer to send detailed information to Apple who will hopefully share it with the application developer if it&#8217;s not their own.</p>
<p>Windows users will want to head to the <em>Event Viewer</em> and find the error and any additional messages that appear to relate to it and included these too.</p>
<h3>Steps to reproduce</h3>
<p>Ideally the minimal number of steps to reproduce the error every time. You want this to be reliable as possible as companies have limited resources too and won&#8217;t spend days trying to reproduce a low-impact bug.</p>
<p>This can be a very important step in understanding the scope of the problem and it&#8217;s impact. If you can&#8217;t reproduce it in a minimal number of steps there&#8217;s always the possibility you&#8217;re overlooking some other aspect that could be causing the problem &#8211; bad data or rogue code elsewhere!</p>
<p>For an application this may be a data file or a number of manual steps a user must manually perform via the user interface.</p>
<p>For a framework a small self-contained project file with a minimal amount of code to reproduce the failing scenario.</p>
<p>Again here, if you can make the steps clear and ideally in the language of the company producing the software your bug report is not going to hit extra delays.</p>
<h3>Environment</h3>
<p>Bugs are often sensitive to their environment and you should always include the version number of the software you are using as well as pertinent platform details,  including:</p>
<ul>
<li>What operating system, version &amp; service pack</li>
<li>What processor architecture (x86, x64, IA-64)</li>
<li>What language &amp; locale your machine is running in (e.g. US English (en-US), Brazil Portuguese (pr-BR))</li>
</ul>
<p>In the specific case of Visual Studio and .NET bugs:</p>
<ul>
<li>What version of Visual Studio you are using (including any service packs)</li>
<li>What processor architecture you are compiling for</li>
<li>What language and compiler version you are using (e.g. C# compiling for 4.0)</li>
</ul>
<p>You may need to include details for your desktop or developer machine <strong>and </strong>details of the server it is connecting to if any are involved.</p>
<h3>What you&#8217;ve tried</h3>
<p>Chances are you tried several things before filing a bug report. Let us know if you tried:</p>
<ul>
<li>Alternate routes through the user interface</li>
<li>Entering data in a different format or order</li>
<li>A different computer or environment</li>
</ul>
<p>Letting them know this means they can avoid suggesting things you&#8217;ve already tried or waste time trying them too.</p>
<p><em>[)amien</em></p>

<p><a href="http://feedads.g.doubleclick.net/~a/mYGh3xJ3udMRA5KfX9Ax9OcWNVI/0/da"><img src="http://feedads.g.doubleclick.net/~a/mYGh3xJ3udMRA5KfX9Ax9OcWNVI/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/mYGh3xJ3udMRA5KfX9Ax9OcWNVI/1/da"><img src="http://feedads.g.doubleclick.net/~a/mYGh3xJ3udMRA5KfX9Ax9OcWNVI/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feed.damieng.com/~ff/DamienG?a=SxbcjpgOZ6M:ciZnIZJFda0:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/DamienG?i=SxbcjpgOZ6M:ciZnIZJFda0:D7DqB2pKExk" border="0"></img></a> <a href="http://feed.damieng.com/~ff/DamienG?a=SxbcjpgOZ6M:ciZnIZJFda0:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/DamienG?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/DamienG/~4/SxbcjpgOZ6M" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://damieng.com/blog/2010/06/30/anatomy-of-a-good-bug-report/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Include for LINQ to SQL (and maybe other providers)</title>
		<link>http://damieng.com/blog/2010/05/21/include-for-linq-to-sql-and-maybe-other-providers?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=include-for-linq-to-sql-and-maybe-other-providers</link>
		<comments>http://damieng.com/blog/2010/05/21/include-for-linq-to-sql-and-maybe-other-providers#comments</comments>
		<pubDate>Fri, 21 May 2010 18:24:16 +0000</pubDate>
		<dc:creator>Damien Guard</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[linq]]></category>
		<category><![CDATA[linq-to-sql]]></category>

		<guid isPermaLink="false">http://damieng.com/?p=1684</guid>
		<description>It&amp;#8217;s quite common that when you issue a query you&amp;#8217;re going to want to join some additional tables. In LINQ this can be a big issue as associations are properties and it&amp;#8217;s easy to end up issuing a query every time you hit one. This is referred to as the SELECT N+1 problem and tools [...]</description>
			<content:encoded><![CDATA[<p>It&#8217;s quite common that when you issue a query you&#8217;re going to want to join some additional tables.</p>
<p>In LINQ this can be a big issue as associations are properties and it&#8217;s easy to end up issuing a query every time you hit one. This is referred to as the <a href="http://l2sprof.com/Learn/Alerts/SelectNPlusOne">SELECT N+1 problem</a> and tools like <a href="http://l2sprof.com/">LINQ to SQL Profiler</a> can help you find them.</p>
<h3>An example</h3>
<p>Consider the following section of C# code that displays a list of blog posts and also wants the author name.</p>
<pre><code><strong>foreach</strong>(Post post <strong>in</strong> db.Posts)
  Console.WriteLine("{0} {1}", post.Title, post.Author.Name);</code></pre>
<p>This code looks innocent enough and will issue a query like &#8220;SELECT * FROM [Posts]&#8221; but iterating over the posts causes the lazy-loading of the Author property to trigger and each one may well issue a query similar to &#8220;SELECT * FROM [Authors] WHERE [AuthorID] = 1&#8243;.</p>
<p>In the case of LINQ to SQL it&#8217;s not always an extra load as it will check the posts AuthorID foreign key in its internal identity map (cache) to see if it&#8217;s already in-memory before issuing a query to the database.</p>
<h3>LINQ to SQL&#8217;s LoadWith</h3>
<p>Most object-relational mappers have a solution for this &#8211; Entity Framework&#8217;s ObjectQuery has an Include operator (that alas takes a string), and <a href="http://ayende.com/Blog/archive/2006/05/02/CombatingTheSelectN1ProblemInNHibernate.aspx">NHibernate has a fetch</a> mechanism. LINQ to SQL has LoadWith which is used like this:</p>
<pre><code><strong>var </strong>db = <strong>new </strong>MyDataContext();
<strong>var </strong>dlo = <strong>new </strong>DataLoadOptions();
dlo.LoadWith&lt;Posts&gt;(p =&gt; p.Blog);
db.LoadOptions = dlo;</code></pre>
<p>This is a one-time operation for the lifetime of this instance of the data context which can be inflexible and LoadWith has at least <a href="http://connect.microsoft.com/VisualStudio/feedback/details/361683/using-dataloadoptions-with-a-linq-to-sql-inheritance-hierarchy-results-in-multiple-sql-left-joins">one big bug with inheritance issuing multiple joins</a>.</p>
<h3>A flexible alternative</h3>
<p>This got me thinking and I came up with a useful extension method to provide Include-like facilities on-demand in LINQ to SQL (and potentially other LINQ providers depending on what they support) in .NET 4.0.</p>
<pre><code><strong>public static</strong> IEnumerable&lt;T&gt; Include&lt;T, TInclude&gt;(<strong>this </strong>IQueryable&lt;T&gt; query, Expression&lt;Func&lt;T, TInclude&gt;&gt; sidecar) {
   <strong>var </strong>elementParameter = sidecar.Parameters.Single();
   <strong>var </strong>tupleType = <strong>typeof</strong>(Tuple&lt;T, TInclude&gt;);
   <strong>var </strong>sidecarSelector =  Expression.Lambda&lt;Func&lt;T, Tuple&lt;T, TInclude&gt;&gt;&gt;(
      Expression.New(tupleType.GetConstructor(<strong>new</strong>[] { <strong>typeof</strong>(T), <strong>typeof</strong>(TInclude) }),
         <strong>new </strong>Expression[] { elementParameter, sidecar.Body  },
         tupleType.GetProperty("Item1"), tupleType.GetProperty("Item2")), elementParameter);
   <strong>return </strong>query.Select(sidecarSelector).AsEnumerable().Select(t =&gt; t.Item1);
}</code></pre>
<p>To use simply place at the <strong>end </strong>of your query and specify the property you wish to eager-load, e.g.</p>
<pre><code><strong>var</strong> oneInclude = db.Posts.Where(p =&gt; p.Published).Include(p =&gt; p.Blog));
<strong>var</strong> multipleIncludes = db.Posts.Where(p =&gt; p.Published).Include(p =&gt; new { p.Blog, p.Template, p.Blog.Author }));</code></pre>
<div class="alert">This code is very untested although it has worked quite well in the few tests I&#8217;ve thrown at it. Evaluate it properly before you decide to use it!</div>
<h3>How it works</h3>
<p>How it works is actually very simple &#8211; it projects into a Tuple that contains the original item and all additional loaded elements and then just returns the query back the original item. It is a dynamic version of:</p>
<pre><code>var query = db.Posts.Where(p =&gt; p.Published).Select(p =&gt; new Tuple(p, p.Blog)).Select(t =&gt; t.Item1);</code></pre>
<p>This is why it has to return IEnumerable&lt;T&gt; and belong at the end (and the use of Tuple is why it is .NET 4.0 only although that should be easy enough to change). Not all LINQ providers will necessarily register the elements with their identity map to prevent SELECT N+1 on lazy-loading but LINQ to SQL does :)</p>
<p><em>[)amien</em></p>

<p><a href="http://feedads.g.doubleclick.net/~a/q-Q61t9fTfY3LBXy196bPtfohUc/0/da"><img src="http://feedads.g.doubleclick.net/~a/q-Q61t9fTfY3LBXy196bPtfohUc/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/q-Q61t9fTfY3LBXy196bPtfohUc/1/da"><img src="http://feedads.g.doubleclick.net/~a/q-Q61t9fTfY3LBXy196bPtfohUc/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feed.damieng.com/~ff/DamienG?a=8dHx3ytBbrk:lA4f2T4Idns:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/DamienG?i=8dHx3ytBbrk:lA4f2T4Idns:D7DqB2pKExk" border="0"></img></a> <a href="http://feed.damieng.com/~ff/DamienG?a=8dHx3ytBbrk:lA4f2T4Idns:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/DamienG?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/DamienG/~4/8dHx3ytBbrk" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://damieng.com/blog/2010/05/21/include-for-linq-to-sql-and-maybe-other-providers/feed</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Creating RSS feeds in ASP.NET MVC</title>
		<link>http://damieng.com/blog/2010/04/26/creating-rss-feeds-in-asp-net-mvc?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=creating-rss-feeds-in-asp-net-mvc</link>
		<comments>http://damieng.com/blog/2010/04/26/creating-rss-feeds-in-asp-net-mvc#comments</comments>
		<pubDate>Mon, 26 Apr 2010 16:45:48 +0000</pubDate>
		<dc:creator>Damien Guard</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[atom]]></category>
		<category><![CDATA[mvc]]></category>
		<category><![CDATA[rss]]></category>

		<guid isPermaLink="false">http://damieng.com/?p=1626</guid>
		<description>ASP.NET&amp;#8217;s MVC -is the technology that brought me to Microsoft and the west-coast and it&amp;#8217;s been fun getting to grips with it these last few weeks. Last week I needed to expose RSS feeds and checked out some examples online but was very disappointed. If you find yourself contemplating writing code to solve technical problems [...]</description>
			<content:encoded><![CDATA[<p>ASP.NET&#8217;s MVC -is the technology that brought me to Microsoft and the west-coast and it&#8217;s been fun getting to grips with it these last few weeks.</p>
<p>Last week I needed to expose RSS feeds and checked out some examples online but was very disappointed.</p>
<p>If you find yourself contemplating writing code to solve technical problems rather than the specific business domain you work in you owe it to your employer and fellow developers to see what exists before churning out code to solve it.</p>
<p>The primary excuse (and I admit to using it myself) is &#8220;X is too bloated, I only need a subset. I can write that quicker than learn their solution.&#8221; but a quick reality check:</p>
<ul>
<li>Time &#8211; code always takes longer than you think.</li>
<li>&#8220;Bloat&#8221; &#8211; indicates the problem is more complex than you realize.</li>
<li>Growth &#8211; todays requirements will grow tomorrow.</li>
<li>Maintenance &#8211; fixing code outside your business domain.</li>
<li>Isolation &#8211; nobody coming in will know your home-grown solution.</li>
</ul>
<p>The RSS examples I found had their own &#8216;feed&#8217; and &#8216;items&#8217; classes and implemented flaky XML rendering by themselves or as MVC view pages.</p>
<p>If these people had spent a little time doing some research they would have discovered .NET&#8217;s built in SyndicatedFeed and SyndicatedItem class for content and two classes (Rss20FeedFormatter and Atom10FeedFormatter )  to handle XML generation with correct encoding, formatting and optional fields.</p>
<p>All that is actually required is a small class to wire up these built-in classes to MVC.</p>
<pre><code><strong>using </strong>System;
<strong>using </strong>System.ServiceModel.Syndication;
<strong>using </strong>System.Text;
<strong>using </strong>System.Web;
<strong>using </strong>System.Web.Mvc;
<strong>using </strong>System.Xml;

<strong>namespace </strong>MyApplication.Something
{
    <strong>public class </strong>FeedResult : ActionResult
    {
        <strong>public </strong>Encoding ContentEncoding { <strong>get</strong>; <strong>set</strong>; }
        <strong>public string </strong>ContentType { <strong>get</strong>; <strong>set</strong>; }

        <strong>private readonly </strong>SyndicationFeedFormatter feed;
        <strong>public </strong>SyndicationFeedFormatter Feed{
            <strong>get </strong>{ <strong>return </strong>feed; }
        }

        <strong>public </strong>FeedResult(SyndicationFeedFormatter feed) {
            <strong>this</strong>.feed = feed;
        }

        <strong>public override void</strong> ExecuteResult(ControllerContext context) {
            <strong>if </strong>(context == <strong>null</strong>)
                <strong>throw new</strong> ArgumentNullException("context");

            HttpResponseBase response = context.HttpContext.Response;
            response.ContentType = !<strong>string</strong>.IsNullOrEmpty(ContentType) ? ContentType : "application/rss+xml";

            <strong>if </strong>(ContentEncoding != <strong>null</strong>)
                response.ContentEncoding = ContentEncoding;

            <strong>if </strong>(feed != <strong>null</strong>)
                <strong>using </strong>(<strong>var </strong>xmlWriter = <strong>new </strong>XmlTextWriter(response.Output)) {
                    xmlWriter.Formatting = Formatting.Indented;
                    feed.WriteTo(xmlWriter);
                }
        }
    }
}</code></pre>
<p>In a controller that supplies RSS feed simply project your data onto SyndicationItems and create a SyndicationFeed then return a FeedResult with the FeedFormatter of your choice.</p>
<pre><code><strong>public </strong>ActionResult NewPosts() {
    <strong>var </strong>blog = data.Blogs.SingleOrDefault();
    <strong>var </strong>postItems = data.Posts.Where(p =&gt; p.Blog = blog).OrderBy(p =&gt; p.PublishedDate).Take(25)
        .Select(p =&gt; new SyndicationItem(p.Title, p.Content, <strong>new </strong>Uri(p.Url)));

    <strong>var </strong>feed = <strong>new </strong>SyndicationFeed(blog.Title, blog.Description, <strong>new </strong>Uri(blog.Url) , postItems) {
        Copyright = blog.Copyright,
        Language = "en-US"
    };

   <strong> return new </strong>FeedResult(<strong>new </strong>Rss20FeedFormatter(feed));
}</code></pre>
<p>This also has a few additional advantages:</p>
<ol>
<li>Unit tests can ensure the ActionResult is a FeedResult</li>
<li>Unit tests can examine the Feed property to examine results without parsing XML</li>
<li>Switching to Atom format involved just changing the new Rss20FeedFormatter to Atom10FeedFormatter</li>
</ol>
<p><em>[)amien</em></p>

<p><a href="http://feedads.g.doubleclick.net/~a/KjnjWEZ5Vxq7LAxbxN_Jk0UCeiI/0/da"><img src="http://feedads.g.doubleclick.net/~a/KjnjWEZ5Vxq7LAxbxN_Jk0UCeiI/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/KjnjWEZ5Vxq7LAxbxN_Jk0UCeiI/1/da"><img src="http://feedads.g.doubleclick.net/~a/KjnjWEZ5Vxq7LAxbxN_Jk0UCeiI/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feed.damieng.com/~ff/DamienG?a=eOV-wiJbBEg:2EK1jLKUBOk:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/DamienG?i=eOV-wiJbBEg:2EK1jLKUBOk:D7DqB2pKExk" border="0"></img></a> <a href="http://feed.damieng.com/~ff/DamienG?a=eOV-wiJbBEg:2EK1jLKUBOk:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/DamienG?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/DamienG/~4/eOV-wiJbBEg" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://damieng.com/blog/2010/04/26/creating-rss-feeds-in-asp-net-mvc/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>MacBook Pro 256GB SSD upgrade experience</title>
		<link>http://damieng.com/blog/2010/04/09/macbook-pro-upgrade-to-crucial-256gb-ssd?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=macbook-pro-upgrade-to-crucial-256gb-ssd</link>
		<comments>http://damieng.com/blog/2010/04/09/macbook-pro-upgrade-to-crucial-256gb-ssd#comments</comments>
		<pubDate>Fri, 09 Apr 2010 23:48:28 +0000</pubDate>
		<dc:creator>Damien Guard</dc:creator>
				<category><![CDATA[Apple]]></category>
		<category><![CDATA[Hardware]]></category>
		<category><![CDATA[crucial]]></category>
		<category><![CDATA[mac]]></category>
		<category><![CDATA[MacBook]]></category>
		<category><![CDATA[MacBook-Pro]]></category>
		<category><![CDATA[ssd]]></category>

		<guid isPermaLink="false">http://damieng.com/?p=1566</guid>
		<description>I&amp;#8217;ve been wanting an SSD for some time and last week I caved. Armed with credit card, screwdriver and trusty MacBook Pro I fitted a sweet SSD and decided to document the experience. Choosing a drive There are a bewildering number of options out there. Budget, as always, dictates the combination of speed and size [...]</description>
			<content:encoded><![CDATA[<p>I&#8217;ve been wanting an SSD for some time and last week I caved. Armed with credit card, screwdriver and <a href="http://damieng.com/blog/2010/01/27/macbook-pro-two-year-check-in">trusty MacBook Pro</a> I fitted a sweet SSD and decided to document the experience.</p>
<h3>Choosing a drive</h3>
<p>There are a bewildering number of options out there. Budget, as always, dictates the combination of speed and size available.</p>
<h4>Size</h4>
<p>You may not need as much space as you think so even if you intend on a fresh install clean-up your current drive to get an idea of requirements.</p>
<p>Remembering to backup before:</p>
<ol>
<li><em>Identify biggest culprits<br />
</em>Try <a href="http://www.daisydiskapp.com/">DaisyDisk</a> ($19) or <a href="http://www.derlien.com/">Disk Inventory X</a> (free) and drill down to catch unexpected bloat in your music library, videos etc.</li>
<li><em>Clean up unused system junk<br />
</em>Use <a href="http://macpaw.com/">CleanMyMac</a> ($30) or <a href="http://monolingual.sourceforge.net/">MonoLingual</a> (free) to clean up logs as well as redundant processor and language support.</li>
<li><em>Archive unused content<br />
</em>Move those podcasts, TV shows, applications and games you aren’t going to use again to cheap external drives.</li>
<li><em>Deal with orphaned &amp; duplicate files<br />
</em>Find media in your iTunes folders missing from iTunes lists and either trash or add it back then use iTune’s <em>Display Duplicates</em>.</li>
</ol>
<p>If you&#8217;re prepared to sacrifice your DVD drive then you can <a href="http://www.ifixit.com/Apple-Parts/12-7-mm-Optical-Bay-SATA-Hard-Drive-Enclosure/IF107-079">move your existing hard drive to the optical bay via an adaptor</a> and purchase a smaller SSD for the OS and key performance-critical files. This saves cash and gives you more space but will cost you battery life.</p>
<h4>Speed</h4>
<p>SSDs are not created equal and the combination of flash and controller (on drive and in your machine) play a part in defining performance. Firmware, hardware revisions, drive size and operating system can also affect the speed so do your homework.</p>
<p><a href="http://anandtech.com/tag/storage">Anandtech</a> have in-depth coverage of SSD’s including an <a href="http://www.anandtech.com/bench/SSD/65">SSD Bench</a> with Tom&#8217;s providing a more general <a href="http://www.tomsguide.com/us/ssd-value-performance,review-1455.html">SSD Buyer&#8217;s Guide</a>. Drives come and go quickly so keep an eye on review dates and exact model numbers as manufacturers have models with similar names with difference specifications.</p>
<h4>My choice &#8211; lightning giant</h4>
<p>I settled on the <a href="http://www.kqzyfj.com/click-3893583-10674245">Crucial RealSSD C300 (CTFDDAC256MAG-1G1)</a> because of it&#8217;s blazingly fast 256GB configuration and my storage requirements were still around 150GB.</p>
<p>This combination doesn&#8217;t come cheap at $699 USD. My links to the Crucial web site include my affiliate code ever optimistic I&#8217;ll get a small commission on a drive or two. (I dream that one day my blog will cover it&#8217;s own hosting charges)</p>
<h4>Some other popular alternatives</h4>
<ul>
<li>Intel&#8217;s X-25M G2 is well regarded and can be had for around $430 for 160GB and $210 for 80GB</li>
<li>Intel&#8217;s X-25V (for value) can be had for around $120 for 40GB</li>
</ul>
<div class="alert">Don&#8217;t go with Apple&#8217;s factory-options for an SSD as they <a href="http://www.anandtech.com/show/2829/19">use slower Samsung drives</a> and charge a premium for it which is unacceptable especially given how easy they are to replace.</div>
<h3>Installing my SSD &amp; Mac OS X (without a DVD drive)</h3>
<p>The newer Unibody MacBook Pro’s hard-drives are designed to be user-replaceable and are covered in the manual.</p>
<p>My non-Unibody is not however those nice chaps over at iFixit have put together a <a href="http://www.ifixit.com/Guide/Repair/Installing-MacBook-Pro-15-Inch-Core-2-Duo-Model-A1211-Hard-Drive-Replacement/459/1">hard drive replacement guide for 15” that is close enough</a> but I have one complication. My DVD drive died which raised the question (and subsequent section)</p>
<blockquote><p>How do I install Snow Leopard without a DVD drive?</p></blockquote>
<h4>Remote Install</h4>
<p><a href="http://support.apple.com/kb/HT2129">Remote Install</a> let&#8217;s you put the a DVD into a machine with a drive, run <em>Utilities</em> &gt; <em>Remote Install</em> and follow a few steps which include holding down the <em>alt</em> key on the machine that doesn’t have a drive.</p>
<p>Unfortunately the machine wanting to boot has to be a Mac mini or a MacBook Air from 2009 or later – i.e. something Apple shipped without a DVD drive.</p>
<h4>NetBoot</h4>
<p>Mac&#8217;s can boot from network images however there are also obstacles here:</p>
<ol>
<li>Apple&#8217;s <a href="http://www.computerworld.com/s/article/9039438/Hands_on_With_Apple_s_NetBoot_Part_2_Creating_and_working_with_images?taxonomyId=157&amp;pageNumber=2">official Netboot server</a> is part of Mac OS X Server and that costs $499</li>
<li>The only <a href="http://www.macgeekery.com/hacks/hardware/make_any_mac_a_netboot_server">unofficial server-less guide</a> I could find is out of date  (nicl &amp; NetInfo were deprecated in Leopard)</li>
</ol>
<p>You will also need to create an image of the Mac OS X DVD to be able to install from.</p>
<h4>USB image</h4>
<p>Your USB device will require over 6.2GB to fit the image of Snow Leopard and need to be partitioned with GUID Partition Table which will wipe it. My 4GB memory stick was too small and I didn&#8217;t want to wipe my 1TB external drive so ended up using my 8GB Compact Flash card.</p>
<p>To get the Snow Leopard DVD copied to it:</p>
<ol>
<li>Use a Mac that has a DVD drive and insert both the install DVD and USB storage device</li>
<li>Launch <em>Disk Utility</em> from the <em>Utilities</em> folder</li>
<li>Select the <em>USB storage device</em> from the list of devices and then choose the <em>Partition</em> tab</li>
<li>Choose <em>1 Partition</em> from the <em>Volume Scheme</em> drop-down</li>
<li>Press <em>Options&#8230;</em> choose <em>GUID Partition Table</em> then <em>OK</em></li>
<li>Press <em>Apply</em> to confirm you are happy to wipe away all the data on the device</li>
<li>Select the <em>install DVD</em> from the list of devices and then choose the <em>Restore</em> tab</li>
<li>Drag the <em>install DVD</em> from the list of devices into the <em>Source</em> text box</li>
<li>Drag the<em> USB storage device</em> from the list of devices into the <em>Destination</em> text box</li>
<li>Press the <em>Restore</em> and wait a while</li>
</ol>
<p>When finished eject the USB device and insert it into your DVD-less Mac. Turn it on holding down <em>alt</em> until a boot selection screen shows and use the arrow keys and return to launch the installer from your USB device.</p>
<p>It may take a while for the installer screen to appear but be patient.</p>
<p>Press <em>Options&#8230;</em> from the installer to turn all off all the features you don&#8217;t need such as additional languages, printer drivers etc.</p>
<div class="information">Open the Installer Log window and set <em>Detail Level</em> to <em>Show All Logs</em> to see more granular progress &#8211; useful if installing from silent media like networks or flash.</div>
<h3>Performance over time &amp; TRIM</h3>
<h4>A simplified primer</h4>
<p>SSDs are fast but the flash technology suffers some limitations most importantly they can&#8217;t overwrite data without erasing it first.</p>
<p>In order to avoid this performance hit, and to preserve the life of the drive itself as blocks can be erased a fine number of times, SSD drives use fresh blocks for as long as they are available. Once they run out every write has to take the hit of an erase and performance can drop to traditional hard-drive speeds (or worse).</p>
<p>The problem arises sooner than you think because file-systems when deleting a file do not actually cause an erase but rather just de-allocate the block knowing it will get overwritten when it&#8217;s next needed so these fresh blocks decrease over time even if you drive never gets full. (Which is how file-recovery tools are able to undelete files)</p>
<p>This doesn&#8217;t sound too bad until you realise that when erasing a file in an operating system the file system just removes the block from it&#8217;s own list to be reused later and therefore the drive itself has no knowledge that the block can be erased until it runs out and starts honoring overwrites.</p>
<h4>The solution</h4>
<p>Manufacturers initially solved this problem by writing tools (for Windows) that examined the file-system structures to find out which blocks are unused so they can send &#8216;erase block&#8217; commands down to the SSD drive and get your performance back &#8211; at least until you run out of blocks again.</p>
<p>This wasn&#8217;t a great solution so they agreed on a standard called &#8216;TRIM&#8217; that lets file-systems tell the drive when blocks are no longer and can be erased in background on-demand. Support was built into Windows 7 and Linux 2.6.28 making a lot of SSD owners very happy.</p>
<h4>Mac OS X &amp; TRIM</h4>
<p>Mac OS X doesn&#8217;t yet support the TRIM command although one <a href="http://osdir.com/ml/darwin-dev/2009-10/msg01698.html">Apple engineer confirmed they are looking at it</a> back in October. They&#8217;re in no hurry as the SSD drives Apple ship don&#8217;t support TRIM yet.</p>
<p>In the mean time you might want to minimize unnecessary writes:</p>
<ol>
<li>Don&#8217;t use Finder&#8217;s Secure Empty Trash or the srm command line tool &#8211; the overwriting they did on magnetic drives doesn&#8217;t overwrite on SSD but steals up to 35x the blocks of the original!</li>
<li>Keep large churning files on external drives (e.g. video processing)</li>
<li>Don&#8217;t let your laptop run out of power as it copies the RAM to disk each time (2-8GB)</li>
<li>Prevent unnecessary disk operations such as the &#8216;last accessed&#8217; attribute on files (see below)</li>
<li>Don&#8217;t keep running disk benchmarks that cause lots of writes!</li>
</ol>
<div class="alert">Don&#8217;t be tempted to try and use one of the manufacturers Windows tools from your BootCamp partition as they only understand NTFS and FAT and won&#8217;t be able to even figure out which blocks can be erased as Mac OS X uses it&#8217;s own HFS+ file system.</div>
<h4>Turn off last-access-time</h4>
<p>These access times are pretty useless and indeed the iPhone also has them switched off. Create a file named noatime.plist in your <em>/Library/LaunchDaemons</em> path with the following contents:</p>
<pre><code>&lt;plist version="1.0"&gt;
  &lt;dict&gt;
    &lt;key&gt;Label&lt;/key&gt;
    &lt;string&gt;noatime&lt;/string&gt;
    &lt;key&gt;ProgramArguments&lt;/key&gt;
    &lt;array&gt;
      &lt;string&gt;mount&lt;/string&gt;
      &lt;string&gt;-vuwo&lt;/string&gt;
      &lt;string&gt;noatime&lt;/string&gt;
      &lt;string&gt;/&lt;/string&gt;
    &lt;/array&gt;
    &lt;key&gt;RunAtLoad&lt;/key&gt;
    &lt;true/&gt;
  &lt;/dict&gt;
&lt;/plist&gt;
</code></pre>
<p>Thanks go to Ricardo Gameiro for that tip although his other <a href="http://blogs.nullvision.com/?p=275">Mac SSD tweaks</a> of creating a RAM disk is questionable given the way Mac OS X manages memory and disabling the RAM copy-to-disk entirely and therefore losing data is more risky to me than running out of blocks early.</p>
<h4>Do not</h4>
<ul>
<li><em>Turn off the sudden motion sensor</em> &#8211; SSDs ignore the park head command anyway</li>
<li><em>Turn off HFS+ journaling</em> &#8211; some users report odd issues and corruption</li>
</ul>
<h4>Last resort</h4>
<p>If you do get into the situation where your write performance is suffering badly and you are prepared to spend a little time to get it back you can do the following:</p>
<ol>
<li>Ensure you have a full Time Machine backup</li>
<li>Boot from a Linux Live CD containing a recent build of <a href="http://sourceforge.net/projects/hdparm/">hdparm</a></li>
<li>Use hdparm to perform an <a href="https://ata.wiki.kernel.org/index.php/ATA_Secure_Erase#HDDErase">ATA Secure Erase</a></li>
<li>Boot from your Mac OS X DVD/USB stick</li>
<li>Choose the <em>Utilities</em> &gt; <em>Restore System From Backup</em> menu option</li>
<li>Point it at your Time Machine backup</li>
</ol>
<p>You should also be able to do this with other full-system backup tools like <a href="http://www.shirt-pocket.com/SuperDuper">SuperDuper</a> but you&#8217;ll have to figure out the steps for yourself ;-)</p>
<h3>Performance</h3>
<p>I wish I had some better benchmarking tools but <a href="http://www.xbench.com/">Xbench</a> is all I have, sorry! It&#8217;s worth bearing in mind that the non-unibody MacBook Pro I have (MacBookPro3,1) is limited to 1.5GB/sec on the SATA bus (despite having an <a href="http://www.intel.com/products/notebook/chipsets/pm965/pm965-overview.htm">Intel ICH-8M SATA controller</a>)</p>
<h4>Xbench HD Test</h4>
<p>My original performance figures with the original as-shipped 0001 firmware and <a href="http://www.crucial.com/support/firmware.aspx">Crucial&#8217;s updated 0002 firmware</a>:</p>
<table>
<tbody>
<tr>
<th></th>
<th>0001<br />
Sequential</th>
<th>0001<br />
Random</th>
<th>0002<br />
Sequential</th>
<th>0002<br />
Random</th>
</tr>
<tr>
<th>Overall</th>
<td style="text-align: right;">137.66</td>
<td style="text-align: right;">643.14</td>
<td style="text-align: right;">137.39</td>
<td style="text-align: right;">648.57</td>
</tr>
<tr>
<th>Uncached write 4K</th>
<td style="text-align: right;">200.40</td>
<td style="text-align: right;">762.30</td>
<td style="text-align: right;">185.92</td>
<td style="text-align: right;">789.45</td>
</tr>
<tr>
<th>Uncached write 256K</th>
<td style="text-align: right;">196.34</td>
<td style="text-align: right;">357.61</td>
<td style="text-align: right;">196.05</td>
<td style="text-align: right;">359.23</td>
</tr>
<tr>
<th>Uncached read 4K</th>
<td style="text-align: right;">67.56</td>
<td style="text-align: right;">1926.31</td>
<td style="text-align: right;">69.27</td>
<td style="text-align: right;">1942.94</td>
</tr>
<tr>
<th>Uncached read 256K</th>
<td style="text-align: right;">239.73</td>
<td style="text-align: right;">628.06</td>
<td style="text-align: right;">238.22</td>
<td style="text-align: right;">624.15</td>
</tr>
</tbody>
</table>
<p><strong>Thoughts</strong></p>
<p>SSD is fast but given the hype I was expecting everything to be instant and it wasn’t quite there. Applications do normally launched within a single dock bounce and everything feels a lot snappier but there wasn&#8217;t the massive WOW! I was expecting &#8211; at least not yet.</p>
<p>There are also a few other advantages often overlooked, especially on a laptop:</p>
<ul>
<li>lower power consumption</li>
<li>less weight, noise &amp; heat</li>
<li>greater shock, dust and magnetic resistance</li>
</ul>
<p>Here&#8217;s a table that pulls the specs compared to the 7200RPM Travestar that was previously my main drive.</p>
<table>
<tbody>
<tr>
<th></th>
<th><a href="http://www.kqzyfj.com/click-3893583-10674245">Crucial RealSSD C300 256GB</a></th>
<th><a href="http://www.hitachigst.com/portal/site/en/menuitem.9958814a08a37d75797ecae2eac4f0a0/">Hitachi Travelstar 7K320</a></th>
</tr>
<tr>
<th>Power consumption (W)</th>
<td style="text-align: right;">0.094 – 2.1 &#8211; 4.3</td>
<td style="text-align: right;">0.2 – 2.2 &#8211; 5.5</td>
</tr>
<tr>
<th>Weight (g)</th>
<td style="text-align: right;">75</td>
<td style="text-align: right;">110</td>
</tr>
<tr>
<th>Shock resistance (G/1.0ms)</th>
<td style="text-align: right;">1500</td>
<td style="text-align: right;">200</td>
</tr>
<tr>
<th>Noise (Bels)</th>
<td style="text-align: right;">0</td>
<td style="text-align: right;">2.8</td>
</tr>
<tr>
<th>Seek time (ms)</th>
<td style="text-align: right;">&lt; .1</td>
<td style="text-align: right;">12</td>
</tr>
</tbody>
</table>
<p>Time will tell how well the machine now deals with large Aperture libraries of RAW images and Visual Studio compilations from inside Parallels and I&#8217;ll be sure to report them here.</p>
<p><em>[)amien</em></p>

<p><a href="http://feedads.g.doubleclick.net/~a/2UGe8NvC8mMLx-fG7iTdFs4qDEA/0/da"><img src="http://feedads.g.doubleclick.net/~a/2UGe8NvC8mMLx-fG7iTdFs4qDEA/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/2UGe8NvC8mMLx-fG7iTdFs4qDEA/1/da"><img src="http://feedads.g.doubleclick.net/~a/2UGe8NvC8mMLx-fG7iTdFs4qDEA/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feed.damieng.com/~ff/DamienG?a=vtOCZ5ZrBLo:SwG3VbWwO_c:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/DamienG?i=vtOCZ5ZrBLo:SwG3VbWwO_c:D7DqB2pKExk" border="0"></img></a> <a href="http://feed.damieng.com/~ff/DamienG?a=vtOCZ5ZrBLo:SwG3VbWwO_c:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/DamienG?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/DamienG/~4/vtOCZ5ZrBLo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://damieng.com/blog/2010/04/09/macbook-pro-upgrade-to-crucial-256gb-ssd/feed</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>My top 5 free VS 2010 extension picks</title>
		<link>http://damieng.com/blog/2010/03/22/my-top-5-free-vs-2010-extension-picks?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=my-top-5-free-vs-2010-extension-picks</link>
		<comments>http://damieng.com/blog/2010/03/22/my-top-5-free-vs-2010-extension-picks#comments</comments>
		<pubDate>Mon, 22 Mar 2010 18:32:33 +0000</pubDate>
		<dc:creator>Damien Guard</dc:creator>
				<category><![CDATA[.NET]]></category>

		<guid isPermaLink="false">http://damieng.com/blog/2010/03/22/my-top-5-free-vs-2010-extension-picks</guid>
		<description>The Visual Studio Gallery is already home to 533 tools, controls and templates for VS 2010 and this number is sure to grow once VS 2010 hits RTM and people get to grips with the extendable new editor. Don’t forget to check out The Visual Studio Blog for more tips, tricks and tools. Theme VS [...]</description>
			<content:encoded><![CDATA[<p>The <a href="http://visualstudiogallery.msdn.microsoft.com/en-us/site/search?f[0].Type=VisualStudioVersion&amp;f[0].Value=10.0&amp;f[0].Text=Visual%20Studio%202010%20RC">Visual Studio Gallery is already home to 533 tools, controls and templates for VS 2010</a> and this number is sure to grow once VS 2010 hits RTM and people get to grips with the <a href="http://msdn.microsoft.com/en-us/library/dd885242(VS.100).aspx">extendable new editor</a>.</p>
<p>Don’t forget to check out <a href="http://blogs.msdn.com/visualstudio/">The Visual Studio Blog</a> for more tips, tricks and tools.</p>
<h3><a href="http://damieng.com/wp-content/uploads/2010/03/smallScreenshot.png"><img style="float: right;" src="http://damieng.com/wp-content/uploads/2010/03/smallScreenshot_thumb.png" alt="Small screenshot of Visual Studio 2010" width="114" height="114" /></a>Theme VS itself</h3>
<p>Color themes for the VS editor have been available and popular for some time but the <a href="http://visualstudiogallery.msdn.microsoft.com/en-us/20cd93a2-c435-4d00-a797-499f16402378">Visual Studio Color Theme Editor</a> adds colour themes to the VS shell letting you customize it to the most intimate detail as well as providing a bunch of pre-defined themes like Aero and shades of XP.</p>
<h3>A bucket and a mop</h3>
<p><a href="http://visualstudiogallery.msdn.microsoft.com/en-us/76293c4d-8c16-4f4a-aee6-21f83a571496">CodeMaid</a> lets you clean up your code more thoroughly and quickly including removing extra empty lines and whitespace and automatically triggering VS’s cleanup steps too (format document, remove unused strings, sort usings) as well as quick switching between project sub-items, quick-jump to complex methods etc.</p>
<h3>Ceasefire on indentation war</h3>
<p>The <a href="http://visualstudiogallery.msdn.microsoft.com/en-us/77b317a9-1a94-4ae0-bd15-d46a3195219f">Indentation Matcher Extension</a> detects the indentation style used when you open a file and sets your VS settings to match meaning you can just edit existing projects and solutions without a care in the world.</p>
<p>As it should be – or at least until <a href="http://en.wikipedia.org/wiki/Elastic_tabstop">Elastic tabstops</a> gets ported to VS2010 which might now be possible.</p>
<h3><a href="http://damieng.com/wp-content/uploads/2010/03/italiccomments.png"><img style="float:right" src="http://damieng.com/wp-content/uploads/2010/03/italiccomments_thumb.png" alt="Italic comments in Visual Studio" width="114" height="114" /></a>Stylistic comments</h3>
<p>My hacked-version of Envy Code R marked italic as bold to trick VS into using it which made a lot of people, myself included, happy. But for those who preferred Consolas it wasn’t much help (there was no way I could redistribute a modified version of Consolas but believe me it looked sweet).</p>
<p>VS 2010 curiously still spurns italic fonts but the pluggable editor means extensions like <a href="http://visualstudiogallery.msdn.microsoft.com/en-us/0b439a8a-e21a-4e26-b82b-054fbf0acab7">ItalicComments</a> can get you there although you’ll need to grab the <a href="http://github.com/noahric/italiccomments">source from gitHub</a> to set it to your coding font of choice given the curious decision to hard-code Lucida Sans.</p>
<h3>My Engrish is gud</h3>
<p>Until Windows gets an OS-level spell checker (OS X had one in 2000) we’ll have to be content with each major app having it’s own or in the case of VS, none.</p>
<p>The aptly-named <a href="http://visualstudiogallery.msdn.microsoft.com/en-us/7c8341f1-ebac-40c8-92c2-476db8d523ce">Spell Checker extension</a> adds English spell checking to comments, HTML text, strings etc. and you too can avoid embarrassing mistakes preserved in source control for all to see.</p>
<p><em>[)amien</em></p>

<p><a href="http://feedads.g.doubleclick.net/~a/gB6gQ2nKKXOdcauskyUpWXq2K8A/0/da"><img src="http://feedads.g.doubleclick.net/~a/gB6gQ2nKKXOdcauskyUpWXq2K8A/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/gB6gQ2nKKXOdcauskyUpWXq2K8A/1/da"><img src="http://feedads.g.doubleclick.net/~a/gB6gQ2nKKXOdcauskyUpWXq2K8A/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feed.damieng.com/~ff/DamienG?a=RK-fxl6baDs:GuPEYGC5Rq8:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/DamienG?i=RK-fxl6baDs:GuPEYGC5Rq8:D7DqB2pKExk" border="0"></img></a> <a href="http://feed.damieng.com/~ff/DamienG?a=RK-fxl6baDs:GuPEYGC5Rq8:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/DamienG?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/DamienG/~4/RK-fxl6baDs" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://damieng.com/blog/2010/03/22/my-top-5-free-vs-2010-extension-picks/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>MacBook Pro two year check-in</title>
		<link>http://damieng.com/blog/2010/01/27/macbook-pro-two-year-check-in?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=macbook-pro-two-year-check-in</link>
		<comments>http://damieng.com/blog/2010/01/27/macbook-pro-two-year-check-in#comments</comments>
		<pubDate>Thu, 28 Jan 2010 07:44:36 +0000</pubDate>
		<dc:creator>Damien Guard</dc:creator>
				<category><![CDATA[Apple]]></category>
		<category><![CDATA[freeware]]></category>
		<category><![CDATA[MacBook-Pro]]></category>

		<guid isPermaLink="false">http://damieng.com/?p=1546</guid>
		<description>It&amp;#8217;s been an interesting couple of years with nothing but a maxed-out MacBook Pro 17&amp;#8243; as my only home machine. Failures The hard drive died but time machine held my hand. At ALT.NET Seattle 2009 my backpack took a dive that left a dent in one corner. The battery was replaced and I roped GrinGod [...]</description>
			<content:encoded><![CDATA[<p>It&#8217;s been an interesting couple of years with nothing but a maxed-out MacBook Pro 17&#8243; as my only home machine.</p>
<h3>Failures</h3>
<p>The hard drive died but time machine held my hand. At <a href="http://www.altnetseattle.org/">ALT.NET Seattle</a> 2009 my backpack took a dive that left a dent in one corner. The battery was replaced and I roped GrinGod into obtaining a replacement UK-style \ key from the UK after some frantic typing.</p>
<p>A friend cracked the display when his keyfob sprang from his Batbelt culminating in a visit of the Apple Store in Bellevue. Ten days and $700 later got that fixed and included a bonus disconnected thermal sensor, a couple of new scratches, an extra screw to rattle around inside and a line of grease around the Apple logo.</p>
<h3>Sticking with it</h3>
<p>When I find myself eying the unibody I wince at the glossy &#8216;matt finish&#8217; screen, the multi-touch trackpad clicks that sound like Robocop is nearby and a US keyboard that requires my pinky to hit a single-height enter key. That little pink dog won&#8217;t learn any new tricks. I&#8217;ve tried.</p>
<p>Still the OpenCL benchmark show the 8600M outperforming the newer 9400M and it does everything I need and at least one thing I don&#8217;t (gets hot enough to bake bread on). Short of switching the hard disk out for an SSD &#8211; I&#8217;ve ordered twice and then recalled after a Twitter volley of &#8220;no, you don&#8217;t want THAT one&#8221; &#8211; it&#8217;s here to stay for at least another year.</p>
<h3>Applications</h3>
<p>One thing that is always changing is the bunch of installed applications as I search for a combination that deliver a nirvana between productivity and enjoyment. Apps that perform a set of focused useful tasks with a shiny, eminently lick-able user interface, score highly.</p>
<p>I&#8217;ve rounded up my favourite apps before but here&#8217;s the latest specials on the menu.</p>
<h4>CleanMyMac</h4>
<p>This great-looking app helps <a href="http://www.macpaw.com/cleanmymac">reclaim wasted space</a> making it a pre-requisite for SSD switchers.</p>
<p>Combining the PowerPC and foreign language code-purging of XSlimmer &amp; TrimTheFat is also adds cache &amp; log purging in with application uninstalls ala AppZapper etc.</p>
<p>Despite using XSlimmer already on my machine it was able to reclaim another 1.8GB and V2 is out soon which I hope will remove &amp; alias duplicates given we&#8217;re not getting ZFS which had this feature (how many copies of Sparkle.framework do I have on my machine&#8230;.)</p>
<h4>Coda</h4>
<p>This year I rewrote my blog&#8217;s WordPress theme from scratch and given the PHP requirement I found myself looking for an alternate IDE to Visual Studio. I already own TextMate but the feel of a raw text editor with bundles of extra bits feel didn&#8217;t have the gloss and usability I wanted such as fast preview, remote FTP sync etc. with a minimal of setup fuss.</p>
<p>I briefly toyed with Espresso during the early development cycle but <a href="http://www.panic.com/coda/">Coda</a> won me over in the end with it&#8217;s sheer simplicity and elegance plus the addition of built-in documentation for PHP was very helpful when working offline.</p>
<h4>BetterTouchTool</h4>
<p>Yes, when the <a href="http://www.apple.com/magicmouse/">Magic Mouse</a> hit the street I picked one up. The idea of a mouse with trackpad multi-touch technology was appealing but a few minutes of use and no amount of twiddling would make it track  or let me configure it to take full advantage of what it should be able to do.</p>
<p>Until Apple sort this out <a href="http://blog.boastr.net/">BetterTouchTool</a> is your friend letting you speed up the tracking of the Magic Mouse, or indeed your trackpad, and assign all sorts of interesting shortcuts and abilities to combinations of finger gestures.</p>
<h4>Secrets</h4>
<p>Mac apps tend to expose only the common options in their user interfaces but sometimes developers add some additional tweaks and settings behind the scenes that live in the Mac&#8217;s equivalent of the registry (known as &#8220;<a href="http://developer.apple.com/mac/library/documentation/Darwin/Reference/ManPages/man1/defaults.1.html">defaults</a>&#8220;). While you can set these manually using the defaults command-line tool you still need to know the setting exists, it&#8217;s name and what options are available and so secrets exposes this.</p>
<p><a href="http://secrets.blacktree.com/">Secrets</a> is similar to Deeper and TinkerTool but the difference is that the secrets web site lets people add new options which then are automatically available within the installed preferences pane making them easily discoverable, searchable, applied&#8230; and occasionally undone.</p>
<h4>Machinarium</h4>
<p><a href="http://damieng.com/wp-content/uploads/2010/01/machinarium2.jpg"><img style="float: right;" title="Machinarium" src="http://damieng.com/wp-content/uploads/2010/01/machinarium2.jpg" alt="Screenshot of the game Machinarium" width="256" height="162" /></a>This <a href="http://machinarium.net/">point-and-click adventure game</a> will appeal to people who enjoyed Monkey Island although it feels more like the gorgeously submerging <a href="http://www.revolution.co.uk/_display.php?id=16">Beneath a Steel Sky</a>.</p>
<p>The scenery is brilliantly imagined, stylistic and shows that very real lived-in cities can be beautiful especially when populated by cute robots capable of assembling themselves from their own body-parts (just like a <a href="http://terminator.wikia.com/wiki/Series_888">triple 8</a> but infinitely cuter).</p>
<p><em>[)amien</em></p>

<p><a href="http://feedads.g.doubleclick.net/~a/K9HqJiLv9eQwt2NwstxMqL5dfZo/0/da"><img src="http://feedads.g.doubleclick.net/~a/K9HqJiLv9eQwt2NwstxMqL5dfZo/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/K9HqJiLv9eQwt2NwstxMqL5dfZo/1/da"><img src="http://feedads.g.doubleclick.net/~a/K9HqJiLv9eQwt2NwstxMqL5dfZo/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feed.damieng.com/~ff/DamienG?a=qlmb0LxmVDU:H3GW61bztY0:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/DamienG?i=qlmb0LxmVDU:H3GW61bztY0:D7DqB2pKExk" border="0"></img></a> <a href="http://feed.damieng.com/~ff/DamienG?a=qlmb0LxmVDU:H3GW61bztY0:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/DamienG?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/DamienG/~4/qlmb0LxmVDU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://damieng.com/blog/2010/01/27/macbook-pro-two-year-check-in/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>LINQ to SQL tips and tricks #3</title>
		<link>http://damieng.com/blog/2010/01/11/linq-to-sql-tips-and-tricks-3?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=linq-to-sql-tips-and-tricks-3</link>
		<comments>http://damieng.com/blog/2010/01/11/linq-to-sql-tips-and-tricks-3#comments</comments>
		<pubDate>Tue, 12 Jan 2010 04:02:37 +0000</pubDate>
		<dc:creator>Damien Guard</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[linq-to-sql]]></category>

		<guid isPermaLink="false">http://damieng.com/?p=1517</guid>
		<description>A few more interesting and lesser-known LINQ to SQL techniques. Lazy loading with stored procedures LINQ to SQL supports stored procedures for retrieving entities, insert, update and delete operations but you can also use them to perform lazy-loading of navigation properties. Lets show an example of a bi-directional relationship between a Post and a Comment. We [...]</description>
			<content:encoded><![CDATA[<p>A few more interesting and lesser-known LINQ to SQL techniques.</p>
<h3>Lazy loading with stored procedures</h3>
<p>LINQ to SQL supports stored procedures for retrieving entities, insert, update and delete operations but you can also use them to perform lazy-loading of navigation properties.</p>
<p>Lets show an example of a bi-directional relationship between a Post and a Comment. We have two stored procedures shown below and we bring them into the DBML by dragging them from <em>Server Explorer</em> into the LINQ to SQL designer surface and we set the return type property for each to the expected entity (Post and Comment respectively).</p>
<pre><code><strong>CREATE PROCEDURE</strong> LoadPost (@PostID <strong>int</strong>) <strong>AS SELECT</strong> * <strong>FROM</strong> Posts <strong>WHERE</strong> ID = @PostID
<strong>CREATE PROCEDURE</strong> LoadComments(@PostID <strong>int</strong>) <strong>AS</strong> <strong>SELECT</strong> * <strong>FROM</strong> Comments <strong>WHERE</strong> Parent_Post_ID = @PostID</code></pre>
<p>This generates two method stubs named LoadPost and LoadComments that we can use to programatically retrieve entities:</p>
<pre><code><strong>var</strong> post = dataContext.LoadPost(1).First();
Console.WriteLine("{0}", post.Title);</code></pre>
<p>Now to replace LINQ to SQL&#8217;s lazy-loading query generation we add  methods to the data context subclass with a specific signature.</p>
<pre><code><strong>partial class </strong>DataClasses1DataContext {
    <strong>protected</strong> IEnumerable&lt;Comment&gt; LoadComments(Post post) {
        <strong>return</strong> <strong>this</strong>.LoadComments(post.ID);
    }

    <strong>protected </strong>Post LoadParentPost(Comment comment) {
        <strong>return</strong> <strong>this</strong>.LoadPost(comment.Post_ID).First();
    }
}</code></pre>
<p>To get the signature of the method names right:</p>
<ol>
<li>Visibility can be anything (protected or private is recommended)</li>
<li>Return type must be the type of the other side of the association (wrapped in IEnumerable&lt;T&gt; when that side can be many)</li>
<li>Method name must start with the word &#8220;Load&#8221;</li>
<li>Method name must then continue with the name of the navigation property you want to intercept</li>
<li>Parameter type must be the type that has the named navigation property (step 4)</li>
</ol>
<h3>Storing and retrieving binary files</h3>
<p>LINQ to SQL supports the SQL Server&#8217;s varbinary type but storing something practical like a file in there isn&#8217;t so clear. Map your varbinary(max) column from your table into your entity which will expose the column as the special System.Data.Linq.Binary type (effectively a wrapper for a byte array but better change tracking).</p>
<h4>File to database</h4>
<p>To store a file in the database just read those bytes in and assign them to the property (Binary knows how to create itself from a byte array automatically). e.g.</p>
<pre><code><strong>string</strong> readPath = @"c:\test.jpg";
<strong>var</strong> storedFile = <strong>new</strong> StoredFile();
storedFile.Binary = File.ReadAllBytes(readPath);
storedFile.FileName = Path.GetFileName(readPath);
data.StoredFiles.InsertOnSubmit(storedFile);</code></pre>
<p>I recommend storing the file name as well as the binary contents for two reasons. Firstly writing the file back to disk or streaming it to a browser will require you know the file type (e.g. .jpg or image/jpeg) and secondly nobody likes downloading a a file called &#8216;download&#8217; or &#8217;1&#8242; :)</p>
<h4>Database to file</h4>
<p>Writing the file back to disk is just as easy although you have to use the ToArray() method of System.Data.Linq.Binary to turn it back into a byte array.</p>
<pre><code><strong>string</strong> writePath = @"c:\temp";
<strong>var</strong> storedFile = data.StoredFiles.First();
File.WriteAllBytes(Path.Combine(writePath, storedFile.FileName), storedFile.Binary.ToArray());
</code></pre>
<div class="alert">Always ensure when writing to the file system based on data that your filenames are sanitized! You don&#8217;t want users overwriting important files on your system.</div>
<h3>Multiple databases with a single context</h3>
<p>Contrary to popular belief you can in fact access entities from multiple databases with a single data context providing they live on the same server. This isn&#8217;t supported but I&#8217;ve used it on my own projects without issue :)</p>
<p>The first part is the tricky bit which involves getting the definition of your entity into your DBML. You have two options here:</p>
<h4>Create a temporary view</h4>
<p>If you have the rights you can temporarily create views in your primary database for each table in your non-primary database.</p>
<pre><code><strong>CREATE VIEW </strong>MyOtherTable <strong>AS SELECT </strong>* <strong>FROM</strong> MyOtherDatabase.dbo.MyOtherTable</code></pre>
<p>Once the views are created add them to your DBML by dragging them from Server Explorer into the LINQ to SQL designer surface and delete the views you created from the database.</p>
<h4>Create a temporary DBML</h4>
<p>If you can&#8217;t or don&#8217;t want to create temporary views then add a second (temporary) LINQ to SQL classes file (DBML) to your project. Use <em>Server Explorer</em> to find your secondary database and drag all the tables you will want to access to the LINQ to SQL designer surface.</p>
<p>Now save &amp; close open files and use the right-mouse-button context menu to <em>Open With&#8230;</em> and choose <em>XML Editor</em> on your original DBML and the new temporary one. Head to the <em>Window</em> menu and select <em>New Vertical Tab Group</em> to make the next step easier.</p>
<p>Looking through the DBML you will see each entity has a &lt;Table&gt; block inside the &lt;Database&gt;. Select all the Table tags and their children (but not Database or Connection) and copy/paste them into your existing DBML file. Then close the files and check all looks well in the designer again.</p>
<p>If it does, delete the temporary DBML file you created. If not go back and check the DBML file for duplicate names, mismatched XML etc.</p>
<h4>Finally, the easy bit</h4>
<p>Open the designer and for each table that comes from the other database select it and change the <em>Source</em> property in the <em>Properties</em> window from <em>dbo.MyOtherTable</em> to <em>MyOtherDatabase.dbo.MyOtherTable</em>.</p>
<p>Hit play and run! <em> </em></p>
<p><em>[)amien</em></p>

<p><a href="http://feedads.g.doubleclick.net/~a/1CWhkeM1bZW7x2g-zzyjP6K0ajQ/0/da"><img src="http://feedads.g.doubleclick.net/~a/1CWhkeM1bZW7x2g-zzyjP6K0ajQ/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/1CWhkeM1bZW7x2g-zzyjP6K0ajQ/1/da"><img src="http://feedads.g.doubleclick.net/~a/1CWhkeM1bZW7x2g-zzyjP6K0ajQ/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feed.damieng.com/~ff/DamienG?a=K4dpEdXdvUA:vlqHLFW-xZY:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/DamienG?i=K4dpEdXdvUA:vlqHLFW-xZY:D7DqB2pKExk" border="0"></img></a> <a href="http://feed.damieng.com/~ff/DamienG?a=K4dpEdXdvUA:vlqHLFW-xZY:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/DamienG?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/DamienG/~4/K4dpEdXdvUA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://damieng.com/blog/2010/01/11/linq-to-sql-tips-and-tricks-3/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Origins of a love affair</title>
		<link>http://damieng.com/blog/2009/12/29/origins-of-a-love-affair?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=origins-of-a-love-affair</link>
		<comments>http://damieng.com/blog/2009/12/29/origins-of-a-love-affair#comments</comments>
		<pubDate>Tue, 29 Dec 2009 20:06:51 +0000</pubDate>
		<dc:creator>Damien Guard</dc:creator>
				<category><![CDATA[Personal]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[bbc micro]]></category>
		<category><![CDATA[sinclair]]></category>

		<guid isPermaLink="false">http://damieng.com/?p=1502</guid>
		<description>From an earliest memory of a cream coloured box emblazoned with letters, mostly black &amp;#8211; some red, came an owl proclaiming allegiance to the BBC. This small box sat silently, patiently even, in our classroom for the best part of a year. On the few occasions our teacher was brave enough to flip the switch [...]</description>
			<content:encoded><![CDATA[<p><a href="http://en.wikipedia.org/wiki/BBC_Micro"><img style="float: right; padding-left: 1em" title="BBC Micro Computer's Owl" src="http://damieng.com/wp-content/uploads/2009/12/bbc-owl.jpg" alt="BBC Micro Computer's Owl" width="147" height="156" /></a>From an earliest memory of a cream coloured box emblazoned with letters, mostly black &#8211; some red, came an owl proclaiming allegiance to the BBC.</p>
<p>This small box sat silently, patiently even, in our classroom for the best part of a year. On the few occasions our teacher was brave enough to flip the switch the machine would chirp into life with it&#8217;s two-tone beep and would state on capital white letters on a black background that it was BASIC. At this point the teacher would key-in the mythical incantation of CHAIN &#8220;&#8221; &#8211; handily jotted on a nearby note &#8211; and feed the beast a cassette tape.</p>
<p>Some time later the machine would announce it&#8217;s vague disappointment with the contents of the tape and be put back to sleep.  One time, and one time only, I recall a screen full of bright colours masquerading as pirates looking for treasure.</p>
<p>I was 11.</p>
<p>Such a tantalising taste of computing left me hungry for more. I knew precisely two people who owned computers. One possessed a cut-down version of the BBC Micro from my classroom called the Acorn Electron and guarded it like a sacred treasure, the other was a friend and more accommodating so much so that he agreed, with little optimism, we could type my program listing into his computer.</p>
<p>What combination of childish scrawl, lack of understanding of programming concepts or the cobbled-together dialect of BASIC was responsible for his <a href="http://en.wikipedia.org/wiki/Texas_Instruments_TI-99/4A">Texas Instruments TI-99</a> rejecting my program I would never know. However neither that failure nor the subsequent arrival and rapid departure of a &#8216;programmable&#8217; <a href="http://computermuseum.50megs.com/brands/g7000.htm">Philips G7000 Videopac</a> from my home would quench my thirst.</p>
<p>A new school year started and for me that meant a new school and new subjects the most interesting of these was named Information Technology or IT for short. I don&#8217;t recall much of these early lessons other than some exposure to word processing, videotext and a simplified geometry-base programming language for drawing shapes called <a href="http://en.wikipedia.org/wiki/Logo_(programming_language)">Logo</a>.</p>
<p>This fixed schedule held little interest to me although the machines themselves did and the teacher opened the room of fifteen or so BBC Micro&#8217;s equipped with 5.25&#8243; floppy drives to the ever-changing line of misfits queued outside to play games. But unlike my old school a few people here actually knew a little about these machines.</p>
<p><a href="http://www.mobygames.com/game/chuckie-egg/">Chuckie Egg</a> and Mr. E were favourites while masochists would fire up <a href="http://video.google.co.uk/videoplay?docid=7967989481850456319&amp;q=castle+quest#">Castle Quest</a>, <a href="http://www.strafom.force9.co.uk/bbc/Retrobbc/Citadel/index.html">Citadel</a> and <a href="http://en.wikipedia.org/wiki/Repton_(video_game)">Repton 2</a> despite being impossible to complete and lacking a crucial save-game option. Fewer still braved the open-ended and <a href="http://en.wikipedia.org/wiki/Elite_(video_game)">Elite</a> space trading/combat game which would let you resume your position each day. Right on commander!</p>
<p>Games consisted of a few files passed between easily damaged 5.25&#8243; floppy disks that students had mysteriously acquired. Remembering which file to CHAIN, *EXEC or *LOAD was a task in itself made worse by the ever-changing scene of kids and games. Now I finally had a machine to myself for a brief period each day I set about solving the first real world problem I encountered here and wanted to create something that would automatically boot and let you select a game by pressing a letter or a number.</p>
<p>Scouring magazines, loaning one of the few <a href="http://mdfs.net/Software/BBCBasic/">BBC BASIC</a> programming manuals from the teacher and occasionally LISTing other people&#8217;s I came up with something that worked. Before long it had double height text, colours and some basic animation. Included in the program were some basic instructions on how to edit the program to fit the games on your own disk and it spread like wildfire.</p>
<p><a href="http://www.worldofspectrum.org"><img style="float: left; padding-right: 1em" title="Spectrum" src="http://damieng.com/wp-content/uploads/2009/12/Spectrum.jpg" alt="" width="202" height="142" /></a>Shortly after my father, who made gadget trading one of his hobbies, brought home a <a href="http://worldofspectrum.org">Sinclair ZX Spectrum</a> 16KB. It was less powerful than the BBC&#8217;s at school and had to be hooked up to a television and cassette record to be of any use and had small rubber keys that were hard to type on. I played and programmed on it for hours without interruption and it finally became mine when my mother made it clear to my father it couldn&#8217;t be traded out for the next gadget. Within a few months the machine had died after something metallic got in through the edge connector.</p>
<p>I was heartbroken but found a neighbour was selling his Spectrum 48K and persuaded my parents to buy it. The extra memory was useful but even better was the hard-key keyboard and the original Sinclair BASIC programming manual I&#8217;d been missing. That year my parents split, my father moved out and we moved to a new parish on our little island of Guernsey which meant new friends and a new school. A school that had IT sharing lessons with technical drawing.</p>
<p>My hopes weren&#8217;t high&#8230;</p>
<p><em>[)amien</em></p>

<p><a href="http://feedads.g.doubleclick.net/~a/DLFlP_JfT8PRkaJh7TmNmpkRmK4/0/da"><img src="http://feedads.g.doubleclick.net/~a/DLFlP_JfT8PRkaJh7TmNmpkRmK4/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/DLFlP_JfT8PRkaJh7TmNmpkRmK4/1/da"><img src="http://feedads.g.doubleclick.net/~a/DLFlP_JfT8PRkaJh7TmNmpkRmK4/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feed.damieng.com/~ff/DamienG?a=A0YQjDsSvVs:c0RO2Zw3CDs:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/DamienG?i=A0YQjDsSvVs:c0RO2Zw3CDs:D7DqB2pKExk" border="0"></img></a> <a href="http://feed.damieng.com/~ff/DamienG?a=A0YQjDsSvVs:c0RO2Zw3CDs:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/DamienG?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/DamienG/~4/A0YQjDsSvVs" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://damieng.com/blog/2009/12/29/origins-of-a-love-affair/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>SQL Server query plan cache – what is it and why should you care?</title>
		<link>http://damieng.com/blog/2009/12/13/sql-server-query-plan-cache?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=sql-server-query-plan-cache</link>
		<comments>http://damieng.com/blog/2009/12/13/sql-server-query-plan-cache#comments</comments>
		<pubDate>Mon, 14 Dec 2009 00:55:42 +0000</pubDate>
		<dc:creator>Damien Guard</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[entity framework]]></category>
		<category><![CDATA[linq-to-sql]]></category>
		<category><![CDATA[sql-server]]></category>

		<guid isPermaLink="false">http://damieng.com/?p=1487</guid>
		<description>What is a query plan? SQL Server like all databases goes through a number of steps when it receives a command. Besides parsing and validating the command text and parameters it looks at the database schema, statistics and indexes to come up with a plan to efficiently query or change your data. You can view [...]</description>
			<content:encoded><![CDATA[<h3>What is a query plan?</h3>
<p>SQL Server like all databases goes through a number of steps when it receives a command. Besides parsing and validating the command text and parameters it looks at the database schema, statistics and indexes to come up with a plan to efficiently query or change your data.</p>
<p>You can view the plan SQL Server comes up with for a given query in SQL Management Studio by selecting Include Actual Execution Plan from the Query menu before running your query.</p>
<div id="attachment_1488" class="wp-caption alignnone" style="width: 310px"><img class="size-medium wp-image-1488" title="A query plan in SQL Managment Studio" src="http://damieng.com/wp-content/uploads/2009/12/QueryPlan-300x141.PNG" alt="A query plan in SQL Managment Studio" width="300" height="141" /><p class="wp-caption-text">A query plan in SQL Managment Studio</p></div>
<h3>Show me the cache!</h3>
<p>Query plans are cached so subsequent identical operations can reuse them for further performance gains. You can see the query plans in use on your server with the following SQL:</p>
<pre><code class="sql">SELECT objtype, p.size_in_bytes, t.[text], usecounts
     FROM sys.dm_exec_cached_plans p
     OUTER APPLY sys.dm_exec_sql_text (p.plan_handle) t
     WHERE objtype IN ('Prepared', 'Adhoc')
     ORDER BY usecounts DESC</code></pre>
<h3>Hitting the cache</h3>
<p>DBAs know the value in hitting the query plan often and this is one of the reasons they like stored procedures. You can however achieve the same thing with parameterized queries providing the query text and the parameter definitions are identical so you can execute the same thing over and over again just with different parameters.</p>
<p>If your ORM uses parameterized queries then it too can take advantage of it but it is important to remember the query definition and parameters need to be identical for this to happen.</p>
<h3>How this applies to ORMs</h3>
<p>In .NET 3.5SP1 both LINQ to SQL and Entity Framework did not set the length of variable type parameters (varchar, nvarchar, text, ntext and varbinary) so SQL Client sets it to the actual content length. This means the cache is often missed and instead populated with plans that are different only in the parameter lengths.</p>
<p>In .NET 4.0 variable length parameters now honour the defined length in both LINQ to SQL and Entity Framework where possible or fall back to the maximum length when the actual content doesn&#8217;t fit in the defined length.</p>
<p><em>[)amien</em></p>

<p><a href="http://feedads.g.doubleclick.net/~a/73SKmygRpm7Fgq-4airO6wRrft4/0/da"><img src="http://feedads.g.doubleclick.net/~a/73SKmygRpm7Fgq-4airO6wRrft4/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/73SKmygRpm7Fgq-4airO6wRrft4/1/da"><img src="http://feedads.g.doubleclick.net/~a/73SKmygRpm7Fgq-4airO6wRrft4/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feed.damieng.com/~ff/DamienG?a=gNs7CEIlVUs:uoTUhkElz18:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/DamienG?i=gNs7CEIlVUs:uoTUhkElz18:D7DqB2pKExk" border="0"></img></a> <a href="http://feed.damieng.com/~ff/DamienG?a=gNs7CEIlVUs:uoTUhkElz18:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/DamienG?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/DamienG/~4/gNs7CEIlVUs" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://damieng.com/blog/2009/12/13/sql-server-query-plan-cache/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Multiple outputs from T4 made easy – revisited</title>
		<link>http://damieng.com/blog/2009/11/06/multiple-outputs-from-t4-made-easy-revisited?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=multiple-outputs-from-t4-made-easy-revisited</link>
		<comments>http://damieng.com/blog/2009/11/06/multiple-outputs-from-t4-made-easy-revisited#comments</comments>
		<pubDate>Fri, 06 Nov 2009 08:20:37 +0000</pubDate>
		<dc:creator>Damien Guard</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[entity framework]]></category>
		<category><![CDATA[linq-to-sql]]></category>
		<category><![CDATA[t4]]></category>

		<guid isPermaLink="false">http://damieng.com/?p=1457</guid>
		<description>My multiple outputs from t4 made easy post contained a class making it easy to produce multiple files from Visual Studio’s text templating engine (T4). While useful it had a few issues: Getting start/end blocks mixed up resulted in unpredictable behaviour Files were rewritten even when content did not change Did not play well with [...]</description>
			<content:encoded><![CDATA[<p>My <a href="http://damieng.com/blog/2009/01/22/multiple-outputs-from-t4-made-easy">multiple outputs from t4 made easy</a> post contained a class making it easy to produce multiple files from Visual Studio’s text templating engine (T4).</p>
<p>While useful it had a few issues:</p>
<ul>
<li>Getting start/end blocks mixed up resulted in unpredictable behaviour</li>
<li>Files were rewritten even when content did not change</li>
<li>Did not play well with source control</li>
<li>Files not always deleted in VS</li>
<li>Failed in Visual Studio&#8217;s project-less Web Sites</li>
</ul>
<p>This helper class forms the basis of multiple file output for Entity Framework templates in .NET 4.0 and the <a href="http://l2st4.codeplex.com">LINQ to SQL templates</a> on CodePlex so we (Jeff Reed, <a href="http://andrewpeters.net/">Andrew Peters</a> and myself) made the following changes.</p>
<h3>Improvements</h3>
<h4>Simpler block handling</h4>
<p>The header, footer and file blocks can now be completed with EndBlock (EndHeader and EndFooter are gone), although it will automatically end the previous block when it hits a new one or the final Process method.</p>
<h4>Skip unchanged files</h4>
<p>Files are now only written to disk if the contents are different with the exception of the original T4 output file (we can&#8217;t stop that, sorry).</p>
<p>There is additional overhead reading and comparing files we believe unmodified files keeping their dates and source control status are worth it.</p>
<h4>Automatic checkout</h4>
<p>When the template detects it is running in Visual Studio and that the file it needs to write to is currently in source control but not checked out it will check the file out for you.</p>
<h4>Predictable clean-up</h4>
<p>All files that were not part of the generation process but are nested under the project item will now be deleted when running inside Visual Studio.</p>
<p>Outside of Visual Studio files are no longer deleted &#8211; this was destructive and it couldn&#8217;t know which files it generated on a previous run to clean-up correctly anyway.</p>
<h4>Website projects fall back to single file generation</h4>
<p>Visual Studio has both <a href="http://damieng.com/blog/2008/02/07/web-site-vs-web-application">web sites and web applications</a> with the former being project-less leading to very messy multi-file generation so it forces single file generation.</p>
<h4>Internal improvements</h4>
<p>Source is now simpler to read and understand with less public visibility and faster and more robust VS interop by batching the files &amp; deletes to a single invoke at the end to avoid conflicts with other add-in&#8217;s that might be triggered by the changes.</p>
<h3>Usage</h3>
<h4>Initialization</h4>
<p>You’ll need to get the code into your template – either copy the code in or reference it with an include directive. Then declare an instance of the Manager class passing in some environmental options such as the desired default output path. (For Visual Studio 2010 remove the #v3.5 portion from the language attribute)</p>
<pre><code>&lt;#@ template language="C#v3.5" hostspecific="True"
#&gt;&lt;#@include file="Manager.ttinclude"
#&gt;&lt;# var manager = Manager.Create(Host, GenerationEnvironment); #&gt;</code></pre>
<h4>File blocks</h4>
<p>Then add one line before and one line after each block which could be split out into it’s own file passing in what the filename would be if split. The EndBlock is optional if you want it to carry through to the next one :)</p>
<pre><code>&lt;# manager.StartNewFile("Employee.generated.cs"); #&gt;
public class Employee { … }
&lt;# manager.EndBlock(); #&gt;</code></pre>
<h4>Headers &amp; footers</h4>
<p>Many templates need to share a common header/footer for such things as comments or using/import statements or turning on/off warnings. Simply use StartHeader and StartFooter and the blocks will be emitted to the start and end of all split files as well as being left in the original output file.</p>
<pre><code>&lt;# manager.StartHeader(); #&gt;
// Code generated by a template
using System;

&lt;# manager.EndBlock(); #&gt;</code></pre>
<h4>Process</h4>
<p>At the end of the template call Process to handle splitting the files (true) or not (false). Anything not included in a specific StartNewFile block will remain in the original output file.</p>
<pre><code>&lt;# manager.Process(true); #&gt;</code></pre>
<h3>Revised Manager class</h3>
<pre><code>&lt;#@ assembly name="System.Core"
#&gt;&lt;#@ assembly name="System.Data.Linq"
#&gt;&lt;#@ assembly name="EnvDTE"
#&gt;&lt;#@ assembly name="System.Xml"
#&gt;&lt;#@ assembly name="System.Xml.Linq"
#&gt;&lt;#@ import namespace="System"
#&gt;&lt;#@ import namespace="System.CodeDom"
#&gt;&lt;#@ import namespace="System.CodeDom.Compiler"
#&gt;&lt;#@ import namespace="System.Collections.Generic"
#&gt;&lt;#@ import namespace="System.Data.Linq"
#&gt;&lt;#@ import namespace="System.Data.Linq.Mapping"
#&gt;&lt;#@ import namespace="System.IO"
#&gt;&lt;#@ import namespace="System.Linq"
#&gt;&lt;#@ import namespace="System.Reflection"
#&gt;&lt;#@ import namespace="System.Text"
#&gt;&lt;#@ import namespace="System.Xml.Linq"
#&gt;&lt;#@ import namespace="Microsoft.VisualStudio.TextTemplating"
#&gt;&lt;#+

// Manager class records the various blocks so it can split them up
<strong>class</strong> Manager {
    <strong>private class</strong> Block {
        <strong>public</strong> String Name;
        <strong>public int </strong>Start, Length;
    }

    <strong>private</strong> Block currentBlock;
    <strong>private</strong> List&lt;Block&gt; files = <strong>new</strong> List&lt;Block&gt;();
    <strong>private</strong> Block footer = <strong>new</strong> Block();
    <strong>private</strong> Block header = <strong>new</strong> Block();
    <strong>private</strong> ITextTemplatingEngineHost host;
    <strong>private</strong> StringBuilder template;
    <strong>protected</strong> List&lt;String&gt; generatedFileNames = <strong>new</strong> List&lt;String&gt;();

    <strong>public static </strong>Manager Create(ITextTemplatingEngineHost host, StringBuilder template) {
        <strong>return</strong> (host <strong>is</strong> IServiceProvider) ? <strong>new</strong> VSManager(host, template) : <strong>new</strong> Manager(host, template);
    }

    <strong>public void</strong> StartNewFile(String name) {
        <strong>if</strong> (name == <strong>null</strong>)
            <strong>throw new</strong> ArgumentNullException("name");
        CurrentBlock = <strong>new</strong> Block { Name = name };
    }

    <strong>public void</strong> StartFooter() {
        CurrentBlock = footer;
    }

    <strong>public void</strong> StartHeader() {
        CurrentBlock = header;
    }

    <strong>public void</strong> EndBlock() {
        <strong>if</strong> (CurrentBlock == <strong>null</strong>)
            <strong>return</strong>;
        CurrentBlock.Length = template.Length - CurrentBlock.Start;
        <strong>if</strong> (CurrentBlock != header &amp;&amp; CurrentBlock != footer)
            files.Add(CurrentBlock);
        currentBlock = <strong>null</strong>;
    }

    <strong>public virtual void</strong> Process(<strong>bool</strong> split) {
        <strong>if</strong> (split) {
            EndBlock();
            String headerText = template.ToString(header.Start, header.Length);
            String footerText = template.ToString(footer.Start, footer.Length);
            String outputPath = Path.GetDirectoryName(host.TemplateFile);
            files.Reverse();
            <strong>foreach</strong>(Block block <strong>in</strong> files) {
                String fileName = Path.Combine(outputPath, block.Name);
                String content = headerText + template.ToString(block.Start, block.Length) + footerText;
                generatedFileNames.Add(fileName);
                CreateFile(fileName, content);
                template.Remove(block.Start, block.Length);
            }
        }
    }

    <strong>protected virtual void</strong> CreateFile(String fileName, String content) {
        <strong>if</strong> (IsFileContentDifferent(fileName, content))
            File.WriteAllText(fileName, content);
    }

    <strong>public virtual</strong> String GetCustomToolNamespace(String fileName) {
        <strong>return null</strong>;
    }

    <strong>public virtual</strong> String DefaultProjectNamespace {
        <strong>get</strong> { <strong>return null</strong>; }
    }

    <strong>protected bool</strong> IsFileContentDifferent(String fileName, String newContent) {
        <strong>return</strong> !(File.Exists(fileName) &amp;&amp; File.ReadAllText(fileName) == newContent);
    }

    <strong>private</strong> Manager(ITextTemplatingEngineHost host, StringBuilder template) {
        <strong>this.</strong>host = host;
        <strong>this</strong>.template = template;
    }

    <strong>private</strong> Block CurrentBlock {
        <strong>get</strong> { <strong>return</strong> currentBlock; }
        <strong>set</strong> {
            <strong>if</strong> (CurrentBlock != <strong>null</strong>)
                EndBlock();
            if<strong> </strong>(value != <strong>null</strong>)
                value.Start = template.Length;
            currentBlock = <strong>value</strong>;
        }
    }

    <strong>private class</strong> VSManager: Manager {
        <strong>private</strong> EnvDTE.ProjectItem templateProjectItem;
        <strong>private</strong> EnvDTE.DTE dte;
        <strong>private</strong> Action&lt;String&gt; checkOutAction;
        <strong>private</strong> Action&lt;IEnumerable&lt;String&gt;&gt; projectSyncAction;

        <strong>public override</strong> String DefaultProjectNamespace {
            <strong>get</strong> {
                <strong>return</strong> templateProjectItem.ContainingProject.Properties.Item("DefaultNamespace").Value.ToString();
            }
        }

        <strong>public override</strong> String GetCustomToolNamespace(string fileName) {
            <strong>return</strong> dte.Solution.FindProjectItem(fileName).Properties.Item("CustomToolNamespace").Value.ToString();
        }

        <strong>public override void</strong> Process(<strong>bool</strong> split) {
            <strong>if</strong> (templateProjectItem.ProjectItems == <strong>null</strong>)
                <strong>return</strong>;
            <strong>base</strong>.Process(split);
            projectSyncAction.EndInvoke(projectSyncAction.BeginInvoke(generatedFileNames, <strong>null</strong>, <strong>null</strong>));
        }

        <strong>protected override void</strong> CreateFile(String fileName, String content) {
            <strong>if</strong> (IsFileContentDifferent(fileName, content)) {
                CheckoutFileIfRequired(fileName);
                File.WriteAllText(fileName, content);
            }
        }

        <strong>internal</strong> VSManager(ITextTemplatingEngineHost host, StringBuilder template)
            : <strong>base</strong>(host, template) {
            <strong>var</strong> hostServiceProvider = (IServiceProvider) host;
            <strong>if</strong> (hostServiceProvider == <strong>null</strong>)
                <strong>throw new</strong> ArgumentNullException("Could not obtain IServiceProvider");
            dte = (EnvDTE.DTE) hostServiceProvider.GetService(<strong>typeof</strong>(EnvDTE.DTE));
            <strong>if</strong> (dte == <strong>null</strong>)
                <strong>throw new</strong> ArgumentNullException("Could not obtain DTE from host");
            templateProjectItem = dte.Solution.FindProjectItem(host.TemplateFile);
            checkOutAction = (String fileName) =&gt; dte.SourceControl.CheckOutItem(fileName);
            projectSyncAction = (IEnumerable&lt;String&gt; keepFileNames) =&gt; ProjectSync(templateProjectItem, keepFileNames);
        }

        <strong>private static void</strong> ProjectSync(EnvDTE.ProjectItem templateProjectItem, IEnumerable&lt;String&gt; keepFileNames) {
            <strong>var</strong> keepFileNameSet = <strong>new</strong> HashSet&lt;String&gt;(keepFileNames);
            <strong>var</strong> projectFiles = <strong>new</strong> Dictionary&lt;String, EnvDTE.ProjectItem&gt;();
            <strong>var</strong> originalFilePrefix = Path.GetFileNameWithoutExtension(templateProjectItem.get_FileNames(0)) + ".";
            <strong>foreach</strong>(EnvDTE.ProjectItem projectItem <strong>in</strong> templateProjectItem.ProjectItems)
                projectFiles.Add(projectItem.get_FileNames(0), projectItem);

            // Remove unused items from the project
            <strong>foreach</strong>(<strong>var</strong> pair <strong>in</strong> projectFiles)
                <strong>if</strong> (!keepFileNames.Contains(pair.Key) &amp;&amp; !(Path.GetFileNameWithoutExtension(pair.Key) + ".").StartsWith(originalFilePrefix))
                    pair.Value.Delete();

            // Add missing files to the project
            <strong>foreach</strong>(String fileName <strong>in</strong> keepFileNameSet)
                <strong>if</strong> (!projectFiles.ContainsKey(fileName))
                    templateProjectItem.ProjectItems.AddFromFile(fileName);
        }

        <strong>private void</strong> CheckoutFileIfRequired(String fileName) {
            <strong>var</strong> sc = dte.SourceControl;
            <strong>if</strong> (sc != <strong>null </strong>&amp;&amp; sc.IsItemUnderSCC(fileName) &amp;&amp; !sc.IsItemCheckedOut(fileName))
                checkOutAction.EndInvoke(checkOutAction.BeginInvoke(fileName, <strong>null</strong>, <strong>null</strong>));
        }
    }
} #&gt;</code></pre>
<p><em>[)amien</em></p>

<p><a href="http://feedads.g.doubleclick.net/~a/ZAmurhau3Q4o7ie9Johck4RF2zk/0/da"><img src="http://feedads.g.doubleclick.net/~a/ZAmurhau3Q4o7ie9Johck4RF2zk/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/ZAmurhau3Q4o7ie9Johck4RF2zk/1/da"><img src="http://feedads.g.doubleclick.net/~a/ZAmurhau3Q4o7ie9Johck4RF2zk/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feed.damieng.com/~ff/DamienG?a=fE2xpQm3c2M:-hPQfCvQv2I:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/DamienG?i=fE2xpQm3c2M:-hPQfCvQv2I:D7DqB2pKExk" border="0"></img></a> <a href="http://feed.damieng.com/~ff/DamienG?a=fE2xpQm3c2M:-hPQfCvQv2I:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/DamienG?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/DamienG/~4/fE2xpQm3c2M" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://damieng.com/blog/2009/11/06/multiple-outputs-from-t4-made-easy-revisited/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>When an object-relational mapper is too much, DataReader too little</title>
		<link>http://damieng.com/blog/2009/09/22/when-an-object-relational-mapper-is-too-much-datareader-too-little?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=when-an-object-relational-mapper-is-too-much-datareader-too-little</link>
		<comments>http://damieng.com/blog/2009/09/22/when-an-object-relational-mapper-is-too-much-datareader-too-little#comments</comments>
		<pubDate>Wed, 23 Sep 2009 06:57:28 +0000</pubDate>
		<dc:creator>Damien Guard</dc:creator>
				<category><![CDATA[.NET]]></category>

		<guid isPermaLink="false">http://damieng.com/blog/2009/09/22/when-an-object-relational-mapper-is-too-much-datareader-too-little</guid>
		<description>I fired up Visual Studio this evening to write a proof-of-concept app and found myself wanting strongly typed domain objects from a database but without the overhead of an object-relational mapper  (the application is read-only). One solution is to write methods by hand, another is to code generate them but it would be nice to [...]</description>
			<content:encoded><![CDATA[<p>I fired up Visual Studio this evening to write a proof-of-concept app and found myself wanting strongly typed domain objects from a database but without the overhead of an object-relational mapper  (the application is read-only).</p>
<p>One solution is to write methods by hand, another is to code generate them but it would be nice to be able to do:</p>
<pre><code><strong>var</strong> customers = <strong>new</strong> SqlCommand("SELECT ID, Name FROM Customer", connection)
  .As(r =&gt; <strong>new</strong> Customer { CustomerID = r.GetInt32(0), Name = r.GetString(1) }).ToList();</code></pre>
<p>So for any DbCommand object you can turn it into a bunch of classes by specifying the new pattern.</p>
<p>The tiny helper class to achieve this is:</p>
<pre><code><strong>public static class</strong> DataHelpers {
    <strong>public static</strong> List&lt;T&gt; ToList&lt;T&gt;(<strong>this</strong> IEnumerable&lt;T&gt; enumerable) {
        <strong>return new</strong> List&lt;T&gt;(enumerable);
    }

    <strong>public static</strong> IEnumerable&lt;T&gt; As&lt;T&gt;(<strong>this</strong> DbCommand command, Func&lt;IDataRecord, T&gt; map) {
        <strong>using</strong> (<strong>var</strong> reader = command.ExecuteReader())
            <strong>while</strong> (reader.Read())
                <strong>yield return</strong> map(reader);
    }
}</code></pre>
<p>It might even be possible to do some cool caching/materialization. I should look into that :)</p>
<p><em>[)amien</em></p>

<p><a href="http://feedads.g.doubleclick.net/~a/8buwrxRAnkbTjGYFhKCf5fMUojE/0/da"><img src="http://feedads.g.doubleclick.net/~a/8buwrxRAnkbTjGYFhKCf5fMUojE/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/8buwrxRAnkbTjGYFhKCf5fMUojE/1/da"><img src="http://feedads.g.doubleclick.net/~a/8buwrxRAnkbTjGYFhKCf5fMUojE/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feed.damieng.com/~ff/DamienG?a=zd0_YURUTh0:ubzw0vAjfW4:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/DamienG?i=zd0_YURUTh0:ubzw0vAjfW4:D7DqB2pKExk" border="0"></img></a> <a href="http://feed.damieng.com/~ff/DamienG?a=zd0_YURUTh0:ubzw0vAjfW4:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/DamienG?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/DamienG/~4/zd0_YURUTh0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://damieng.com/blog/2009/09/22/when-an-object-relational-mapper-is-too-much-datareader-too-little/feed</wfw:commentRss>
		<slash:comments>19</slash:comments>
		</item>
		<item>
		<title>Five steps to blog (re)design</title>
		<link>http://damieng.com/blog/2009/09/11/5-steps-to-blog-redesign?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=5-steps-to-blog-redesign</link>
		<comments>http://damieng.com/blog/2009/09/11/5-steps-to-blog-redesign#comments</comments>
		<pubDate>Fri, 11 Sep 2009 09:10:28 +0000</pubDate>
		<dc:creator>Damien Guard</dc:creator>
				<category><![CDATA[Design]]></category>
		<category><![CDATA[960 grid]]></category>
		<category><![CDATA[web design]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://damieng.com/?p=1336</guid>
		<description>For some time I&amp;#8217;ve wanted to refresh the design here at damieng.com which evolved out of the Redoable theme with my own tweaks to colours, typography, images and background until it was almost my own. Almost, but not quite. As an engineer I prefer incremental improvement over a complete redesign but I was at the [...]</description>
			<content:encoded><![CDATA[<p>For some time I&#8217;ve wanted to refresh the design here at damieng.com which evolved out of the <a href="http://deanjrobinson.com/projects/redoable/">Redoable</a> theme with my own tweaks to colours, typography, images and background until it was almost my own.</p>
<p>Almost, but not quite.</p>
<p>As an engineer I prefer incremental improvement over a complete redesign but I was at the point where the code-base (HTML, CSS and PHP) was unworkable. Partly my fault, partly the sheer complexity of a general-purpose theme with wide-ranging plugin support I didn&#8217;t need.</p>
<p>These are the steps that helped me get to a  clean minimal code-base that did exactly what I wanted and would like to share the experience for friends about to go through a similar process.</p>
<h3>1. Decide on a layout</h3>
<p><a href="http://damieng.com/wp-content/uploads/2009/09/damienglayout1.png"><img src="http://damieng.com/wp-content/uploads/2009/09/damienglayout_thumb1.png" alt="Layout of DamienG.com" style="float:right" /></a>Getting layouts right across browsers can be tricky.</p>
<p>Thankfully a number of individuals have put together a number of <a href="http://net.tutsplus.com/html-css-techniques/which-css-grid-framework-should-you-use-for-web-design/">reusable CSS frameworks</a> that provide grid-based approaches to layout, compensating for differences in browser defaults and including some minimalistic styling.</p>
<p>These let you hit the ground running but they are not complete themes unless you&#8217;re into minimalistic design.</p>
<p>I&#8217;m not a fan of fixed-width sites that contribute to the years of wear on my scrolling mouse finger so settled on the <a href="http://www.designinfluences.com/fluid960gs/">Fluid 960 Grid System</a> which scales a 12 or 16 column grid system out to the full browser width while being incredibly easy to use and tweak.</p>
<p>At this point you&#8217;ll want to copy the CSS they provide into your own development folder and take the existing HTML sample page and cut it down to the bare minimum of &lt;head&gt; and its necessary &lt;link…&gt; elements to setup the CSS plus the &lt;body&gt; and any intermediate child elements required to get the basic structure in place.</p>
<p>Now think about how many columns each section needs to cover and whether it should continue taking columns to the right or whether it should start on a new row after the existing section has finished.</p>
<p>Given I wanted the layout shown above I needed just three containers – the primary left area (red) would span 12 columns and would contain the branding, navigation and actual content. The right area (blue) would span 4 columns and contain the sidebar. As I didn&#8217;t want my footer too high on pages with small amounts of content I created another section (not pictured) that also spanned 12 columns but would appear after the content in both sections. Simply:</p>
<pre><code class="html">&lt;body&gt;
&lt;div class="container_16"&gt;
   &lt;div class="grid_12"&gt;
       &lt;a href="http://damieng.com/" /&gt;
       &lt;ul class="nav" /&gt;
       &lt;div id="maincontent" /&gt;
   &lt;/div&gt;
   &lt;div class="grid_4" id="sidebar" /&gt;
   &lt;div class="clear" /&gt;
   &lt;div class="grid_12" id="footer" /&gt;
&lt;/div&gt;
&lt;/body&gt;</code></pre>
<h3>2. Add your content</h3>
<p>Unless you&#8217;re planning on throwing away any of your content (not recommended if you have it), now is the time to drop in actual content, navigation and any chrome. At this stage real static HTML content is best – the combination of PHP, remotely uploading files and hooking in to dynamic content can really slow you down while you are trying to get the basics sorted.</p>
<p>The easiest thing to do here is to just view source a page on your blog and copy out the required blocks. For me this was:</p>
<ul>
<li>Two blog posts from the main page, they sit in the <em>maincontent</em> div above, each contained within a new <em>&lt;div class=&#8221;article&#8221;&gt;</em> so I can provide article-specific styling</li>
<li>A brand new set of nested navigation elements created by hand based on the page structure – initially two levels deep to support the drop-down CSS menus</li>
<li>My five sidebar elements – <em>Search, Stay in touch, Topics, My most popular</em> and <em>Interesting finds</em></li>
</ul>
<p>Bear in mind that you are going to need to keep the structure and content of your existing pages and articles unless you have the time to either go-back and edit each one or apply some bulk-changes via SQL UPDATE statements. For me, this meant keeping my post sub-headings as <em>&lt;h3&gt;</em> and sticking with my <em>class=&#8221;alert&#8221;, class=&#8221;code&#8221;</em> and  <em>class=&#8221;download&#8221;</em> blocks I use for notifications, code snippets and downloads which required bringing some CSS elements in from the old theme.</p>
<h3>3. Style the page</h3>
<p>Design inspiration can come from many places &#8211; here are some best-of designs, portfolios and showcases to draw from:</p>
<ul>
<li><a href="http://cssbased.com/showcase/">CSS Showcase</a></li>
<li><a href="http://cssbased.com/showcase/"></a><a href="http://www.smashingmagazine.com/2009/07/22/50-new-beautiful-blog-designs/">50 New Beautiful Blog Designs</a></li>
<li><a href="http://www.instantshift.com/2009/09/13/70-fresh-and-inspirational-blog-designs/">70 Fresh and Inspirational Blog Designs</a></li>
<li><a href="http://www.instantshift.com/2009/09/17/70-ultimate-round-up-of-free-psd-website-templates/">70+ Ultimate Round-Up of Free PSD Website Templates</a></li>
</ul>
<p>Now you have some basic HTML and CSS displaying real content it&#8217;s easy to see what works and what doesn&#8217;t with minimal resistance to experimenting.</p>
<p>I was happy with the existing look and I plan on further tweaks now my code-base is easy to understand so for now took the basic colours, background and icons then adjusted the layout, spacing, positioning, wording and elements like the content metadata. This was also an opportunity to experiment with some <a href="http://www.smashingmagazine.com/2009/07/20/50-new-css-techniques-for-your-next-web-design/">CSS techniques available</a> but considering CSS3 browser support is limited right now I kept this to:</p>
<ul>
<li><em>@font-face</em> for headings – <a href="http://www.fontsquirrel.com/fontface">Font Squirrel have a great set of @font-face kits</a> including fonts with the CSS snippets</li>
<li><em>text-shadow</em> for headings and hyperlink hover-overs to achieve a glow effect</li>
<li><em>border-radius</em> for curved blocks and navigation bar (also used prior to the redesign)</li>
<li>JavaScript to upgrade the search-box from <em>type=&#8221;text&#8221; </em>to <em>type=&#8221;search&#8221;</em> in Safari</li>
</ul>
<p>The result is something that looks quite unique on Safari and Chrome yet still looks good on Internet Explorer 7.</p>
<h3>4. Convert to a theme</h3>
<p>Now our CSS and HTML looks great as a single page we need to create a theme for the blog engine. This consists of several specially-named files to dynamically construct the page as required.</p>
<p>You can build this from scratch but a basic theme like <a href="http://elliotjaystocks.com/blog/free-starkers-wordpress-theme/">Starkers &#8216;naked&#8217; WordPress theme</a> is recommended. Merge the layout and style of your theme with the dynamic tags that drop in content, navigation and titles in from the basic theme. A quick start would be to modify:</p>
<ul>
<li><strong>header.php</strong> with your HTML up to opening your main content div but:
<ul>
<li>remove <em>&lt;link type=&#8221;text/css&#8221;&gt;</em> elements to the CSS and replace with the one line <em>&lt;link&gt;</em> from the theme</li>
<li>replace the static navigation elements with a call to a function to dynamically build it such as <em>&lt;?php wp_list_pages(&#8216;depth=3&amp;title_li=&#8217;); ?&gt;</em></li>
<li>links for shortcut icons and ensure they point to files that exist, you don&#8217;t want to be serving up 404 error pages every time</li>
<li>meta tags – take the dynamic ones with <em>&lt;?php?&gt;</em> elements (content-type, description etc). from the theme and merge them with your sites existing ones if you have any</li>
</ul>
</li>
<li><strong>sidebar.php</strong> with your HTML from closing the main content div through to closing the sidebar div</li>
<li><strong>footer.php</strong> with your HTML footer div (and in my case the preceding clear div) through to the end of the file</li>
<li><strong>single.php</strong> with your HTML that appears around each article with the necessary tags (like <em>&lt;?php the_content(); ?&gt;</em> taken from the naked theme)</li>
<li><strong>style.css</strong> with relative references to your CSS files and your new metadata, e.g.</li>
</ul>
<pre><code class="css">/*
Theme Name: DamienGNew
Theme URI: http://damieng.com
Description: Minimalistic theme based on Fluid 960 Grid.
Version: 1
Author: Damien Guard
Author URI: http://damieng.com
*/
@import "css/reset.css";
@import "css/grid.css";
@import "css/damieng.css";
@import "css/navigation.css";</code></pre>
<p>Rename the theme folder and upload it to your blog in the right location – for WordPress this is <em>wp-content/themes</em>.</p>
<h3>5. Test drive, tweak, rinse and repeat</h3>
<p>Now you want to test the theme without interrupting the existing one so don&#8217;t go and set it to be the default just yet.</p>
<p>If you are using WordPress a few tips:</p>
<ol>
<li><a href="http://ocaoimh.ie/wp-super-cache/">WP Super Cache</a> enabled sites &#8211; check <em>Don&#8217;t cache pages for logged in users</em> so you don&#8217;t see cached pages in the original theme pages or serve up pre-cached new themed pages for other visitors</li>
<li><a href="http://www.prelovac.com/vladimir/wordpress-plugins/theme-test-drive">Theme Test Drive</a> – lets you specify a new theme and what access level it applies to (e.g. 10 for admin) so you will see it while you are logged in for testing</li>
<li>Page templates &#8211;  leave them to last as WordPress will try to use them in the default theme too</li>
<li>Keep an eye out for<em> error_log</em> files &#8211; they contain details of when pages failed</li>
</ol>
<p>It&#8217;s worth testing your site in popular browser and operating system combinations from your own analytics or you don&#8217;t have any of your own stats check out <a href="http://en.wikipedia.org/wiki/Usage_share_of_web_browsers">usage share of web browsers at Wikipedia</a>. The major engines are:</p>
<ul>
<li><strong>Internet Explorer </strong>(Windows)</li>
<li><strong>WebKit</strong> (Safari on OS X, Chrome on Windows &amp; Konqueror on Linux)</li>
<li><strong>Gecko</strong> (Firefox cross-platform &amp; Camino on Mac)</li>
<li><strong>Opera</strong> (cross-platform)</li>
</ul>
<p>Bear in mind that each browser can behave quite differently between versions &#8211; <a title="Virtual machine images for Internet Explorer" href="http://www.microsoft.com/downloads/details.aspx?FamilyId=21EABB90-958F-4B64-B5F1-73D0A413C8EF&amp;displaylang=en">Internet Explorer 6</a> will likely render quite differently to 7 or 8.</p>
<p>Sites like <a href="http://browsershots.org/">BrowserShots</a> can help by rendering your page on a multitude of browsers for you and present screen-shots (once the theme is live) to compare. Validating your <a href="http://validator.w3.org/">HTML</a> and <a href="http://jigsaw.w3.org/css-validator/">CSS</a> is a good idea because the errors and warnings it spots are the likely cause for odd rendering problems.</p>
<p>Now you see a single blog post rendered it&#8217;s time to go through the rest of the files and apply the same merging process before you sit back, smile and make your new theme the default.</p>
<p><em>[)amien</em></p>

<p><a href="http://feedads.g.doubleclick.net/~a/TLCBaQBLqasVrc7R5K96tcCdaUE/0/da"><img src="http://feedads.g.doubleclick.net/~a/TLCBaQBLqasVrc7R5K96tcCdaUE/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/TLCBaQBLqasVrc7R5K96tcCdaUE/1/da"><img src="http://feedads.g.doubleclick.net/~a/TLCBaQBLqasVrc7R5K96tcCdaUE/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feed.damieng.com/~ff/DamienG?a=6Ph33T3Mb6M:SYw7t7PylZU:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/DamienG?i=6Ph33T3Mb6M:SYw7t7PylZU:D7DqB2pKExk" border="0"></img></a> <a href="http://feed.damieng.com/~ff/DamienG?a=6Ph33T3Mb6M:SYw7t7PylZU:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/DamienG?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/DamienG/~4/6Ph33T3Mb6M" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://damieng.com/blog/2009/09/11/5-steps-to-blog-redesign/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>First impressions of Snow Leopard</title>
		<link>http://damieng.com/blog/2009/08/29/first-impressions-of-snow-leopard?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=first-impressions-of-snow-leopard</link>
		<comments>http://damieng.com/blog/2009/08/29/first-impressions-of-snow-leopard#comments</comments>
		<pubDate>Sat, 29 Aug 2009 08:14:19 +0000</pubDate>
		<dc:creator>Damien Guard</dc:creator>
				<category><![CDATA[Apple]]></category>
		<category><![CDATA[Fonts]]></category>
		<category><![CDATA[Mac-OS-X]]></category>
		<category><![CDATA[snow leopard]]></category>

		<guid isPermaLink="false">http://damieng.com/?p=1273</guid>
		<description>I came home from work today to find my family pack upgrade version of Snow Leopard. It&amp;#8217;s been a few hours, so here are impressions so far. Packaging &amp;#38; installation The packaging was very small and lightweight and eco-friendly compared to the big-plastic-box-monsters that come out of Redmond. Installation went mostly smoothly apart from an [...]</description>
			<content:encoded><![CDATA[<p>I came home from work today to find my family pack upgrade version of Snow Leopard. It&#8217;s been a few hours, so here are impressions so far.</p>
<h3>Packaging &amp; installation</h3>
<p>The packaging was very small and lightweight and eco-friendly compared to the big-plastic-box-monsters that come out of Redmond.</p>
<p>Installation went mostly smoothly apart from an abort-and-restart that seems to have been caused by my DVD drive flaking out on me. It&#8217;s been trouble since it came back from the Apple Store.</p>
<p>I had to run the separate Xcode installer to update that &#8211; it wasn&#8217;t automatically detected &#8211; which left me wondering if I need to manually install anything from the optional installs or not. Running Xcode before updating it not only failed to launch but left a background process I had to force quit with Actitity Monitor to let the installer upgrade it.</p>
<p>The less-is-more-approach followed through to disk space which freed up another 10.5 GB &#8211; impressive given that I had purged all the non-English language resources already using Monolingual and I elected to re-install the Rossetta PowerPC binary support.</p>
<h3>Noticeable changes</h3>
<p>Despite being an optimization release Apple squeezed a few features in to sweeten the deal the majority of which are documented at their site and in proper reviews. The ones I&#8217;ve encountered so far are:</p>
<h4>Location services, detect time-zone</h4>
<p><img src="http://images.damieng.com/blog/snow-timezone.png" alt="Screenshot of location aware time-zone in Snow Leopard" style="float:right" />Great for travelling users like myself, it found my nearest city instantly.</p>
<h4>AirPort status in menu bar</h4>
<p>Pop-up menu now shows signal strength of all other networks. (Hold down alt when popping up this menu to see detailed connection stats)</p>
<h4>Smoothing options</h4>
<p>Gone are the Automatic, light, medium and strong options replaced with a single &#8220;Use LCD font smoothing when available&#8221; option that <a href="http://blog.jjgod.org/2009/08/18/snow-leopard-vs-dell-lcd-displays/">isn&#8217;t too good at detecting third-party displays but you can activate the old hidden options</a>.</p>
<h4>Subpixel quality</h4>
<p>The rendering just looks plain wrong when booting. It has that awful colour-fringe that you see from time to time, the cause of which seems to be related to the default gamma (the curve on which digital colours become analogue levels) on <a href="http://support.apple.com/kb/HT3712?viewlocale=en_US">Mac OS X changing from 1.8 to the PC compatible 2.2</a>.</p>
<p>It seems however that the sub-pixel rendering algorithms haven&#8217;t been updated to correct this. There is absolutely no point in posting a screenshot as either your browser, screen or OS would make it appear different to how it did here.</p>
<p>Help is at hand though, you can head into the ColorSync Utility in your Applications folder and calibrate your display &#8211; just follow the instructions and set the gamma back to 1.8. It&#8217;s worth turning on &#8220;Expert&#8221; mode and spending a few minutes setting it up properly though.</p>
<h4>Unable to open NIBs</h4>
<p><img src="http://images.damieng.com/blog/no-compiled-nibs.png" alt="No compiled nibs error in Snow Leopard"  style="float:right" />I used to love opening up other people&#8217;s NIB files. You could in theory create your own customised versions of an applications interface. Localise it for yourself. Maybe even create a UK English version where Colour is spelt correctly.</p>
<p>No more.</p>
<p>Whether this was to save space or to prevent such hacking is anyone&#8217;s guess.</p>
<h3>Compatibility woes</h3>
<p>So far I&#8217;ve had a couple of things break:</p>
<ul>
<li><a href="http://cyberduck.ch/">Cyberduck</a> quits on launch &#8211; beta replacement is out</li>
<li>Xbox 360 controller extension (I don&#8217;t use it anymore anyway)</li>
<li><a href="http://www.islayer.com/apps/istatmenus/">iStat Menus</a> fails to launch &#8211; I need this to replace menu time with timezones and a drop-down calendar</li>
</ul>
<h3>Features I was expecting</h3>
<p>Given the lean-and-mean plus sensible small refinements I was expecting&#8230;</p>
<ol>
<li>Login Window keyboard shortcut &#8211; come on, seriously, with the secrecy at Apple surely you need this too?</li>
<li>Uninstaller &#8211; AWOL since the transition from OpenStep to NextStep and sorely needed</li>
<li>Language purging &#8211; I still don&#8217;t want French etc. on my laptop, odd omission given the reduction goals</li>
<li>System update framework &#8211; Other apps could use this too you know guys &#8211; and put clever delta&#8217;ing support in</li>
<li>Grab &#8211; STILL only saves in TIFF format. So I save it there, load into preview then into PNG. WTF??</li>
<li>Safari &#8211; should have an option to force new windows to open in a new tab</li>
</ol>
<p>I&#8217;d also love to see being able to pin documents to their dock icon and being able to push a window to an edge to tile like as these were two features I found useful in Windows 7. Talking of which when you hold the mouse button down on a dock icon it greys everything else out for a truly UAC-like moment every time you want to quit an app from the dock&#8230;</p>
<h3>The Menlo font</h3>
<p><a href="http://typophile.com/node/58625"><img src="http://images.damieng.com/blog/menlo-vs-vera.png" alt="Menlo and Vera Sans Mono overlaid for comparison" style="float:right" /></a>Apple needed to replace the ageing Monaco as it has poor international unicode support, has just a single style and poor hinting (it uses embedded bitmaps to look good without anti-aliasing in Terminal).</p>
<p>Given <a href="http://news.stanford.edu/news/2005/june15/jobs-061505.html">Steve Job&#8217;s apparently love of typography</a> would they commission a gorgeous new monospaced font as Microsoft did with <a href="http://www.ascendercorp.com/font/consolas/">Consolas</a>? No.</p>
<p>In 2003 Bitstream released the family <a href="http://www.gnome.org/fonts/">Bitstream Vera</a> under a free licence which included a great Sans Mono with bolt, italic and bold-italic variants. It even has some capable hinting so looks pretty good without anti-aliasing although could do with a few delta&#8217;s to clean that up. While it was short on the unicode support several forks filled in the gaps such as Deja Vu and Apple took Vera Sans Mono, grabbed some of these additions (adding 2900 glyphs) and tweaked some of the existing ones. Specifically they moved the vertical bar up on EBH, widened MN, shifted il, changed 0 from dotted to crossed and move/resized punctation then packed it up in a True Type Collection file that stores multiple TTF&#8217;s in a single file.</p>
<p>While these changes themselves look quite good &#8211; it seems they were optimizing for 14 point &#8211; in the process they destroyed the hinting for these glyphs despite the tiny amount of change made.<br />
<img src="http://images.damieng.com/blog/menlo-notepad.png" alt="Menlo on Windows in Notepad" /><img src="http://images.damieng.com/blog/menlo-aliased.png" alt="Menlo on Mac OS X in TextMate" /><br />
Spot which ones Apple modified on these screenshots (curiously Windows refuses to use the TTC file as it believes it is corrupt).</p>
<p><img src="http://images.damieng.com/blog/no-aliased-menlo.png" alt="Screenshot of Terminal preferences showing anti-aliasing forced for Menlo" style="float:left" />Apple is obviously aware it&#8217;s not a good job as the option to turn off anti-aliasing in Terminal when using Menlo is curiously disabled &#8211; this seems to be something hard-coded into Terminal.app as it doesn&#8217;t affect TextMate.</p>
<h3>Boot Camp</h3>
<p>Installation here was a little tricky as initially the installer told me that Boot Camp 64-bit was not supported on my computer model.</p>
<p>Whether they don&#8217;t support 64-bit Windows on a late 2007 MacBook Pro 17&#8243; (MacBookPro3,1) or whether it was complaining about Windows 7 isn&#8217;t clear as there are no Windows 7 specific drivers on the disk. </p>
<p>All is not lost however as if you navigate into Boot Camp\Drivers\Apple folder you can run the BootCamp.msi or BootCamp64.msi from there and it does not seem to perform the check. All the drivers installed without complaint and the trackpad, mouse, audio etc. is working just fine.</p>
<p><em>[)amien</em></p>

<p><a href="http://feedads.g.doubleclick.net/~a/IV_ioQWuiPgdPoFkTNs9gm_7_kU/0/da"><img src="http://feedads.g.doubleclick.net/~a/IV_ioQWuiPgdPoFkTNs9gm_7_kU/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/IV_ioQWuiPgdPoFkTNs9gm_7_kU/1/da"><img src="http://feedads.g.doubleclick.net/~a/IV_ioQWuiPgdPoFkTNs9gm_7_kU/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feed.damieng.com/~ff/DamienG?a=BYkSzcGVqYQ:yYUBRUgWS48:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/DamienG?i=BYkSzcGVqYQ:yYUBRUgWS48:D7DqB2pKExk" border="0"></img></a> <a href="http://feed.damieng.com/~ff/DamienG?a=BYkSzcGVqYQ:yYUBRUgWS48:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/DamienG?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/DamienG/~4/BYkSzcGVqYQ" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://damieng.com/blog/2009/08/29/first-impressions-of-snow-leopard/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>LINQ to SQL cheat sheet</title>
		<link>http://damieng.com/blog/2009/08/12/linq-to-sql-cheat-sheet?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=linq-to-sql-cheat-sheet</link>
		<comments>http://damieng.com/blog/2009/08/12/linq-to-sql-cheat-sheet#comments</comments>
		<pubDate>Thu, 13 Aug 2009 07:55:33 +0000</pubDate>
		<dc:creator>Damien Guard</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[cheat sheet]]></category>
		<category><![CDATA[linq-to-sql]]></category>

		<guid isPermaLink="false">http://damieng.com/?p=1248</guid>
		<description>A few short words to say I&amp;#8217;ve put together a cheat sheet for LINQ to SQL with one page for C# and another for VB.NET. It shows the syntax for a number of common query operations, manipulations and attributes and can be a very useful quick reference :) Download LINQ to SQL cheat sheet (PDF) [...]</description>
			<content:encoded><![CDATA[<p>A few short words to say I&#8217;ve put together a cheat sheet for LINQ to SQL with one page for C# and another for VB.NET.</p>
<p><img src="http://images.damieng.com/blog/LINQToSQLCheatSheet.png" alt="Thumbnail of the LINQ to SQL Cheat Sheet PDF" /></p>
<p>It shows the syntax for a number of common query operations, manipulations and attributes and can be a very useful quick reference :)</p>
<p class="download">Download <a href="http://download.damieng.com/dotnet/LINQToSQLCheatSheet.pdf">LINQ to SQL cheat sheet (PDF)</a> (76 KB)</p>
<p><em>[)amien</em></p>

<p><a href="http://feedads.g.doubleclick.net/~a/DqW43_l0ScN8Rac7kIPOusNZ7lo/0/da"><img src="http://feedads.g.doubleclick.net/~a/DqW43_l0ScN8Rac7kIPOusNZ7lo/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/DqW43_l0ScN8Rac7kIPOusNZ7lo/1/da"><img src="http://feedads.g.doubleclick.net/~a/DqW43_l0ScN8Rac7kIPOusNZ7lo/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feed.damieng.com/~ff/DamienG?a=dWz3A5BInTk:ug7UQwy5YKk:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/DamienG?i=dWz3A5BInTk:ug7UQwy5YKk:D7DqB2pKExk" border="0"></img></a> <a href="http://feed.damieng.com/~ff/DamienG?a=dWz3A5BInTk:ug7UQwy5YKk:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/DamienG?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/DamienG/~4/dWz3A5BInTk" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://damieng.com/blog/2009/08/12/linq-to-sql-cheat-sheet/feed</wfw:commentRss>
		<slash:comments>20</slash:comments>
		</item>
		<item>
		<title>Dictionary look-up or create made simpler</title>
		<link>http://damieng.com/blog/2009/08/04/dictionaryt-look-up-or-create-made-simpler?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=dictionaryt-look-up-or-create-made-simpler</link>
		<comments>http://damieng.com/blog/2009/08/04/dictionaryt-look-up-or-create-made-simpler#comments</comments>
		<pubDate>Wed, 05 Aug 2009 00:24:04 +0000</pubDate>
		<dc:creator>Damien Guard</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[C#]]></category>

		<guid isPermaLink="false">http://damieng.com/blog/2009/08/04/dictionaryt-look-up-or-create-made-simpler</guid>
		<description>The design of a Dictionary&amp;#60;T&amp;#62; lends itself well to a caching or identification mechanism and as a result you often see code that looks like this: private static Dictionary&amp;#60;string,Employee&amp;#62; employees; … public static Employee GetByName(string name) { Employee employee; if (!employees.TryGetValue(name, out employee)) { employee = new Employee(whatever); employees.Add(name, employee); } return employee; } It&amp;#8217;s [...]</description>
			<content:encoded><![CDATA[<p>The design of a Dictionary&lt;T&gt; lends itself well to a caching or identification mechanism and as a result you often see code that looks like this:</p>
<pre><code><strong>private static</strong> Dictionary&lt;<strong>string</strong>,Employee&gt; employees;
…
<strong>public static</strong> Employee GetByName(<strong>string</strong> name) {
    Employee employee;
    <strong>if</strong> (!employees.TryGetValue(name, <strong>out</strong> employee)) {
        employee = <strong>new</strong> Employee(whatever);
        employees.Add(name, employee);
    }
    <strong>return</strong> employee;
}</code></pre>
<p>It&#8217;s not that it is particularly difficult but it can be a bit error prone and when you’re doing it over and over. What would be nicer is something that let you do:</p>
<pre><code><strong>public static</strong> Employee GetByName(<strong>string</strong> name) {
    <strong>return</strong> employees.GetOrAdd(name, () =&gt; <strong>new</strong> Employee(whatever));
}</code></pre>
<p>Here&#8217;s an extension method to drop-in to a static class of your choosing that achieves just that.</p>
<pre><code><strong><strong>public </strong>static</strong> TActualValue GetOrAdd&lt;TKey, TDictionaryValue, TActualValue&gt;(<strong>this</strong> IDictionary&lt;TKey, TDictionaryValue&gt; dictionary, TKey key, Func&lt;TActualValue&gt; newValue) <strong>where</strong> TActualValue : TDictionaryValue
{
    TDictionaryValue value;
    <strong>if</strong> (!dictionary.TryGetValue(key, <strong>out</strong> value)) {
        value = newValue.Invoke();
        dictionary.Add(key, value);
    }
    <strong>return</strong> (TActualValue)value;
}</code></pre>
<p><em>[)amien</em></p>

<p><a href="http://feedads.g.doubleclick.net/~a/yIYLd3BLDQ2fPWekyyoPUizutq0/0/da"><img src="http://feedads.g.doubleclick.net/~a/yIYLd3BLDQ2fPWekyyoPUizutq0/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/yIYLd3BLDQ2fPWekyyoPUizutq0/1/da"><img src="http://feedads.g.doubleclick.net/~a/yIYLd3BLDQ2fPWekyyoPUizutq0/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feed.damieng.com/~ff/DamienG?a=PCHi-9YFXNw:nWT9DdP8JbE:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/DamienG?i=PCHi-9YFXNw:nWT9DdP8JbE:D7DqB2pKExk" border="0"></img></a> <a href="http://feed.damieng.com/~ff/DamienG?a=PCHi-9YFXNw:nWT9DdP8JbE:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/DamienG?d=qj6IDK7rITs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/DamienG/~4/PCHi-9YFXNw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://damieng.com/blog/2009/08/04/dictionaryt-look-up-or-create-made-simpler/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
	</channel>
</rss><!-- Dynamic page generated in 3.347 seconds. --><!-- Cached page generated by WP-Super-Cache on 2010-07-28 19:28:03 --><!-- Compression = gzip -->
