<?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://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:blogChannel="http://backend.userland.com/blogChannelModule" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">
  <channel>
    <title>Dmitri Nesteruk</title>
    <description>Personal blog on .Net and other matters</description>
    <link>http://nesteruk.org/blog/</link>
    <docs>http://www.rssboard.org/rss-specification</docs>
    <generator>BlogEngine.NET 1.4.5.0</generator>
    <language>en-US</language>
    <blogChannel:blogRoll>http://nesteruk.org/blog/opml.axd</blogChannel:blogRoll>
    <blogChannel:blink>http://www.dotnetblogengine.net/syndication.axd</blogChannel:blink>
    <dc:creator>Dmitri Nesteruk</dc:creator>
    <dc:title>Dmitri Nesteruk</dc:title>
    <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/nesteruk" type="application/rss+xml" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><item>
      <title>Simpler MVC localization</title>
      <description>&lt;p&gt;I&amp;rsquo;ve been working on a typical implementation of Asp.Net MVC localization. However, unlike the textbook examples, I wanted to have just the language, not the culture, feature in my paths. Specifically, intead of writing &lt;code&gt;http://mydomain.com/en-US/&lt;/code&gt; I wanted to be able to write just &lt;code&gt;http://mydomain.com/en/&lt;/code&gt;. Unfortunately, you cannot set the &lt;code&gt;CurrentCulture&lt;/code&gt; variable to a &amp;lsquo;neurtal&amp;rsquo; culture. Consequently, what I ended up doing is keeping a dictionary of cultures and applying the default one whenever needed:&lt;/p&gt;

&lt;blockquote&gt;&lt;code&gt;&lt;font size="2" face="Consolas, Andale Mono, Courier New, Courier" color="black"&gt;&lt;font color="#0000FF"&gt;public&lt;/font&gt;&amp;nbsp;&lt;font color="#0000FF"&gt;class&lt;/font&gt;&amp;nbsp;InternationalizationAttribute&amp;nbsp;:&lt;br/&gt;
&amp;nbsp;&amp;nbsp;ActionFilterAttribute&lt;br/&gt;
{&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&lt;font color="#0000FF"&gt;private&lt;/font&gt;&amp;nbsp;&lt;font color="#0000FF"&gt;static&lt;/font&gt;&amp;nbsp;Dictionary&amp;lt;&lt;font color="#0000FF"&gt;string&lt;/font&gt;,&amp;nbsp;&lt;font color="#0000FF"&gt;string&lt;/font&gt;&amp;gt;&amp;nbsp;cultureMappings&amp;nbsp;=&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#0000FF"&gt;new&lt;/font&gt;&amp;nbsp;Dictionary&amp;lt;&lt;font color="#0000FF"&gt;string&lt;/font&gt;,&amp;nbsp;&lt;font color="#0000FF"&gt;string&lt;/font&gt;&amp;gt;&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;font color="#570000"&gt;"en"&lt;/font&gt;,&amp;nbsp;&lt;font color="#570000"&gt;"US"&lt;/font&gt;},&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;font color="#570000"&gt;"sv"&lt;/font&gt;,&amp;nbsp;&lt;font color="#570000"&gt;"SE"&lt;/font&gt;},&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;font color="#570000"&gt;"ru"&lt;/font&gt;,&amp;nbsp;&lt;font color="#570000"&gt;"RU"&lt;/font&gt;}&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;};&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&lt;font color="#0000FF"&gt;public&lt;/font&gt;&amp;nbsp;&lt;font color="#0000FF"&gt;override&lt;/font&gt;&amp;nbsp;&lt;font color="#0000FF"&gt;void&lt;/font&gt;&amp;nbsp;OnActionExecuting(ActionExecutingContext&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;filterContext)&lt;br/&gt;
&amp;nbsp;&amp;nbsp;{&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#0000FF"&gt;string&lt;/font&gt;&amp;nbsp;language&amp;nbsp;=&amp;nbsp;(&lt;font color="#0000FF"&gt;string&lt;/font&gt;)filterContext.RouteData.Values[&lt;font color="#570000"&gt;"language"&lt;/font&gt;]&amp;nbsp;??&amp;nbsp;&lt;font color="#570000"&gt;"en"&lt;/font&gt;;&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#0000FF"&gt;string&lt;/font&gt;&amp;nbsp;culture&amp;nbsp;=&amp;nbsp;cultureMappings[language];&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#0000FF"&gt;try&lt;/font&gt;&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Thread.CurrentThread.CurrentCulture&amp;nbsp;=&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;CultureInfo.GetCultureInfo(language&amp;nbsp;+&amp;nbsp;&lt;font color="#570000"&gt;"-"&lt;/font&gt;&amp;nbsp;+&amp;nbsp;culture);&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Thread.CurrentThread.CurrentUICulture&amp;nbsp;=&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;CultureInfo.GetCultureInfo(language&amp;nbsp;+&amp;nbsp;&lt;font color="#570000"&gt;"-"&lt;/font&gt;&amp;nbsp;+&amp;nbsp;culture);&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&amp;nbsp;&lt;font color="#0000FF"&gt;catch&lt;/font&gt;&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br/&gt;
&amp;nbsp;&amp;nbsp;}&lt;br/&gt;
}&lt;br/&gt;
&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;
&lt;p&gt;I don&amp;rsquo;t know, though, maybe there&amp;rsquo;s a better way of doing this.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/Lc-GrX5Lcm0" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/Lc-GrX5Lcm0/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/Simpler-MVC-localization.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=863f681f-71f9-4531-8a58-c77cb690c960</guid>
      <pubDate>Wed, 11 Nov 2009 10:31:00 +0300</pubDate>
      <category>asp.net</category>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=863f681f-71f9-4531-8a58-c77cb690c960</pingback:target>
      <slash:comments>0</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=863f681f-71f9-4531-8a58-c77cb690c960</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/Simpler-MVC-localization.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=863f681f-71f9-4531-8a58-c77cb690c960</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=863f681f-71f9-4531-8a58-c77cb690c960</feedburner:origLink></item>
    <item>
      <title>Improving business orientation</title>
      <description>&lt;p&gt;Throughought my development career, I always thought of IT as self-serving. The idea of software actually servicing a business didn&amp;rsquo;t escape me, but it was never as pertinent as the pursuit of software for the &lt;em&gt;art&lt;/em&gt; of it instead of its usefulness. I guess I&amp;rsquo;m old enough now to realize that this is a key issue with software altogether &amp;ndash; that we often like it for the wrong reasons.&lt;/p&gt;

&lt;p&gt;So what am I going to do about it? A couple of things.&lt;/p&gt;

&lt;p&gt;First, I will stop writing technology articles of the self-serving variety. I think I&amp;rsquo;ll write more on how IT helps business, rather than on how IT does something fantastic internally. Don&amp;rsquo;t get me wrong, technical articles will be there too.&lt;/p&gt;

&lt;p&gt;Also, I will focus more on domain-specific issues, rather than abstract examples. Specifically, I want to write more about business intelligence (BI), which should be useful not just to programmers, but also to people who are interested in technology applications in business.&lt;/p&gt;

&lt;p&gt;I will also start thinking more about ways in which all our technical wizardry can be used to improve our own business. This &amp;lsquo;eating our dogfood&amp;rsquo; approach is precisely what technology companies should be doing more of. I&amp;rsquo;m pretty sure one can get economical benefits by applying your own technical expertise in running a business.&lt;/p&gt;

&lt;p&gt;Wish me luck.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/FVBtIdJR8k0" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/FVBtIdJR8k0/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/Improving-business-orientation.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=4dbfd69e-7880-40ce-accb-03aa038e6996</guid>
      <pubDate>Thu, 05 Nov 2009 23:20:00 +0300</pubDate>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=4dbfd69e-7880-40ce-accb-03aa038e6996</pingback:target>
      <slash:comments>0</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=4dbfd69e-7880-40ce-accb-03aa038e6996</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/Improving-business-orientation.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=4dbfd69e-7880-40ce-accb-03aa038e6996</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=4dbfd69e-7880-40ce-accb-03aa038e6996</feedburner:origLink></item>
    <item>
      <title>Use ASP.NET to collect visitor stats from blogs you do not own (but can post in)</title>
      <description>&lt;p&gt;This is a quickie post explaining how to use ASP.NET in order to collect visitor statistics on a page which does not allow JavaScript. The idea is simple &amp;ndash; you place a 1&amp;times;1px transparent GIF onto the image, with the GIF&amp;rsquo;s address being on your server.&lt;/p&gt;

&lt;p&gt;The GIF actually points to a typical ASPX page, i.e., you write something like the following:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;code&gt;&amp;lt;img src="http://mysite/stats/default.aspx"/&amp;gt;&lt;/code&gt;
&lt;/blockquote&gt;
&lt;p&gt;The page &lt;code&gt;default.aspx&lt;/code&gt; is a basic WebForms page. Its statistical tracking is done in the &lt;code&gt;Page_Load()&lt;/code&gt; method, the contents of the ASPX file being completely irrelevant for our purposes.&lt;/p&gt;

&lt;p&gt;Three things happen in &lt;code&gt;Page_Load()&lt;/code&gt;. First, since we don&amp;rsquo;t want our service abused, we check that the page that sent the request is &amp;lsquo;legit&amp;rsquo;. If you don&amp;rsquo;t do this, people will figure out that you have a service, and might even try to DDoS you just for the fun of it. I also check that the IP isn&amp;rsquo;t mine, so that my own visits to the page do not count.&lt;/p&gt;

&lt;blockquote&gt;&lt;code&gt;&lt;font size="2" face="Consolas, Andale Mono, Courier New, Courier" color="black"&gt;&lt;font color="#0000FF"&gt;private&lt;/font&gt;&amp;nbsp;&lt;font color="#0000FF"&gt;static&lt;/font&gt;&amp;nbsp;&lt;font color="#0000FF"&gt;readonly&lt;/font&gt;&amp;nbsp;&lt;font color="#0000FF"&gt;string&lt;/font&gt;[]&amp;nbsp;permittedURLs&amp;nbsp;=&amp;nbsp;&lt;font color="#0000FF"&gt;new&lt;/font&gt;[]&lt;br/&gt;
{&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&lt;font color="#570000"&gt;"http://site.com/page/"&lt;/font&gt;&lt;br/&gt;
};&lt;br/&gt;
&lt;font color="#0000FF"&gt;protected&lt;/font&gt;&amp;nbsp;&lt;font color="#0000FF"&gt;void&lt;/font&gt;&amp;nbsp;Page_Load(&lt;font color="#0000FF"&gt;object&lt;/font&gt;&amp;nbsp;sender,&amp;nbsp;EventArgs&amp;nbsp;e)&lt;br/&gt;
{&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&lt;font color="#0000FF"&gt;if&lt;/font&gt;&amp;nbsp;(Request.UrlReferrer&amp;nbsp;==&amp;nbsp;&lt;font color="#0000FF"&gt;null&lt;/font&gt;&amp;nbsp;||&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Array.IndexOf(permittedURLs,&amp;nbsp;Request.UrlReferrer.AbsoluteUri)&amp;nbsp;==&amp;nbsp;-1&amp;nbsp;||&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Request.UserHostAddress&amp;nbsp;==&amp;nbsp;&lt;font color="#570000"&gt;"1.2.3.4"&lt;/font&gt;)&amp;nbsp;&lt;font color="#006400"&gt;//&amp;nbsp;my&amp;nbsp;IP&amp;nbsp;address&lt;br/&gt;&lt;/font&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#0000FF"&gt;return&lt;/font&gt;;&lt;br/&gt;
}&lt;br/&gt;
&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;
&lt;p&gt;If any of the checks fail, we &lt;code&gt;return&lt;/code&gt; from the page, yielding the ASPX content instead of the image. If they succeed, we add an entry to the database. The example below uses LINQ2SQL in order to add an entry concerning the time the page was accessed, the IP of whoever accessed it, and the page it was accessed from.&lt;/p&gt;

&lt;blockquote&gt;&lt;code&gt;&lt;font size="2" face="Consolas, Andale Mono, Courier New, Courier" color="black"&gt;&lt;font color="#0000FF"&gt;using&lt;/font&gt;&amp;nbsp;(&lt;font color="#0000FF"&gt;var&lt;/font&gt;&amp;nbsp;dc&amp;nbsp;=&amp;nbsp;&lt;font color="#0000FF"&gt;new&lt;/font&gt;&amp;nbsp;VisitsDataContext())&lt;br/&gt;
{&lt;br/&gt;
&amp;nbsp;&amp;nbsp;Visit&amp;nbsp;v&amp;nbsp;=&amp;nbsp;&lt;font color="#0000FF"&gt;new&lt;/font&gt;&amp;nbsp;Visit();&lt;br/&gt;
&amp;nbsp;&amp;nbsp;v.DateAndTime&amp;nbsp;=&amp;nbsp;DateTime.Now;&lt;br/&gt;
&amp;nbsp;&amp;nbsp;v.IPAddress&amp;nbsp;=&amp;nbsp;Request.UserHostAddress;&lt;br/&gt;
&amp;nbsp;&amp;nbsp;v.ReferrerURL&amp;nbsp;=&amp;nbsp;Request.UrlReferrer&amp;nbsp;!=&amp;nbsp;&lt;font color="#0000FF"&gt;null&lt;/font&gt;&amp;nbsp;?&amp;nbsp;Request.UrlReferrer.AbsoluteUri&amp;nbsp;:&amp;nbsp;&lt;font color="#0000FF"&gt;null&lt;/font&gt;;&lt;br/&gt;
&amp;nbsp;&amp;nbsp;dc.Visits.InsertOnSubmit(v);&lt;br/&gt;
&amp;nbsp;&amp;nbsp;dc.SubmitChanges();&lt;br/&gt;
}&lt;br/&gt;
&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;
&lt;p&gt;For safety, I check referrer for &lt;code&gt;null&lt;/code&gt;, which helps with debugging. Now, with that done, I load up a 1-pixel GIF (which I keep in the same folder) and serve it. Then, I end the response so that the ASPX doesn&amp;rsquo;t get sent after the image data.&lt;/p&gt;

&lt;blockquote&gt;&lt;code&gt;&lt;font size="2" face="Consolas, Andale Mono, Courier New, Courier" color="black"&gt;&lt;font color="#0000FF"&gt;using&lt;/font&gt;&amp;nbsp;(Bitmap&amp;nbsp;bmp&amp;nbsp;=&amp;nbsp;(Bitmap)Bitmap.FromFile(Server.MapPath(&lt;font color="#570000"&gt;"OnePixel.gif"&lt;/font&gt;)))&lt;br/&gt;
{&lt;br/&gt;
&amp;nbsp;&amp;nbsp;Response.ContentType&amp;nbsp;=&amp;nbsp;&lt;font color="#570000"&gt;"image/gif"&lt;/font&gt;;&lt;br/&gt;
&amp;nbsp;&amp;nbsp;bmp.Save(Response.OutputStream,&amp;nbsp;ImageFormat.Gif);&lt;br/&gt;
}&lt;br/&gt;
Response.End();&lt;br/&gt;
&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;
&lt;p&gt;Using the code shown, you can easily and discreetly collect usage statistics from any web-resource which you do not own but can post images on.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/Gv6694y07T4" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/Gv6694y07T4/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/Use-ASPNET-to-collect-visitor-stats-from-blogs-you-do-not-own-(but-can-post-in).aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=307651bd-c8b1-49ec-a4a4-3b6000a1e518</guid>
      <pubDate>Tue, 03 Nov 2009 22:35:00 +0300</pubDate>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=307651bd-c8b1-49ec-a4a4-3b6000a1e518</pingback:target>
      <slash:comments>1</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=307651bd-c8b1-49ec-a4a4-3b6000a1e518</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/Use-ASPNET-to-collect-visitor-stats-from-blogs-you-do-not-own-(but-can-post-in).aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=307651bd-c8b1-49ec-a4a4-3b6000a1e518</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=307651bd-c8b1-49ec-a4a4-3b6000a1e518</feedburner:origLink></item>
    <item>
      <title>Outsourcing vs Custom Development</title>
      <description>&lt;p&gt;I don&amp;rsquo;t like the term &amp;lsquo;outsourcing&amp;rsquo;. In fact, if you visit our &lt;a href="http://activemesa.com"&gt;company site&lt;/a&gt;, you&amp;rsquo;ll find no mention of &amp;lsquo;outsourcing&amp;rsquo;, &amp;lsquo;offshore&amp;rsquo; and similar terms. Maybe I&amp;rsquo;m being unfair here, but there seem to be some sort of negative connotation associated with the term, and I prefer the term &amp;lsquo;custom development&amp;rsquo; (or just &amp;lsquo;custom dev&amp;rsquo;) instead. The way I see it,&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Outsourcing&lt;/strong&gt; = hiring developers because they are &lt;strong&gt;cheap&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Custom development&lt;/strong&gt; = hiring developers because they are &lt;strong&gt;brilliant&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The not-so-subtle difference has to do with the way people view software development generally, applying inappropriate measurement techniques when assessing the efficacy of software development. See, unlike mechanical engineering, where a part&amp;rsquo;s production time is fixed and predictable, software engineering is creative and non-linear, which implies that conventional economic models of &amp;lsquo;parts per hour&amp;rsquo; are all but useless.&lt;/p&gt;

&lt;p&gt;Now, it&amp;rsquo;s not just that. The quality of manufactured parts typically doesn&amp;rsquo;t vary much. With quality control, person A is roughly as good as person B in terms of making some part or other. The difference of 2&amp;times; is not significant. In software development, the difference can be 100x, but while quality differs vastly, &lt;strong&gt;wages do not&lt;/strong&gt;. This makes the idea of &amp;lsquo;cheap developers&amp;rsquo; somewhat silly, because developers by and large distribute themselves evenly on the wage scale &lt;strong&gt;whatever the wages are&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Now, if projects succeeded regularly, you might argue that I&amp;rsquo;m wrong and it doesn&amp;rsquo;t matter. But projects fail. As in EPIC FAIL. Projects mess up due to a zillion reasons, making a truly shocking statistic for an industry that is &lt;strong&gt;supposed to&lt;/strong&gt; be precise and ultra-efficient (hey, we have measurement tools and all that, right?). Somehow, I&amp;rsquo;m thinking, the idea of having &lt;strong&gt;brilliant&lt;/strong&gt; developers (managers, qa engineers, etc.) actually fits into the larger idea of actually &lt;strong&gt;making the project on time and budget&lt;/strong&gt;. Which is what this business is all about, last time I checked.&lt;/p&gt;

&lt;p&gt;The moral of the story is this: custom development companies like mine will &lt;strong&gt;never&lt;/strong&gt; be cheap, but will make every effort to product &lt;strong&gt;good software&lt;/strong&gt;. Which is why we&amp;rsquo;re in this business altogether.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/FvHAYm-vvLk" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/FvHAYm-vvLk/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/Outsourcing-vs-Custom-Development.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=31a55974-bb69-4147-81e0-8008012bf8d4</guid>
      <pubDate>Wed, 28 Oct 2009 19:53:00 +0300</pubDate>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=31a55974-bb69-4147-81e0-8008012bf8d4</pingback:target>
      <slash:comments>1</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=31a55974-bb69-4147-81e0-8008012bf8d4</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/Outsourcing-vs-Custom-Development.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=31a55974-bb69-4147-81e0-8008012bf8d4</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=31a55974-bb69-4147-81e0-8008012bf8d4</feedburner:origLink></item>
    <item>
      <title>Looking for projects on freelance sites</title>
      <description>&lt;p&gt;I&amp;rsquo;ve recently been investigating various freelance sites, such as Rent-a-Coder, looking for juicy contracts to pick up and, to be honest, I&amp;rsquo;m amazed by people&amp;rsquo;s mentality. For example, I saw a contract that I really liked &amp;ndash; it was in line with our expertise, the client seemed serious, but&amp;hellip; they&amp;rsquo;re looking to pay $1500-5000 on what is basically about $100k of development effort.&lt;/p&gt;

&lt;p&gt;Now, this got me thinking: obviously we won&amp;rsquo;t be bidding for such a contract, but other people will. Can they really offer such an amount of development effort? Even if we assume that rates on freelance sites are a lot smaller than ours, I&amp;rsquo;m thinking that people still need to make a profit, right? Either that, or everyone out there is out to con unsuspecting buyers of their money. Because it looks like you&amp;rsquo;ve got a buyer who wants a BMW but only has enough for a Lada. Do they get a BMW? I don&amp;rsquo;t think so.&lt;/p&gt;

&lt;p&gt;The economics of freelance sites are bewildering.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/5jEnVzFW0HQ" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/5jEnVzFW0HQ/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/Looking-for-projects-on-freelance-sites.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=482a7d3a-ff62-442e-bab1-f5caab578937</guid>
      <pubDate>Mon, 26 Oct 2009 18:37:00 +0300</pubDate>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=482a7d3a-ff62-442e-bab1-f5caab578937</pingback:target>
      <slash:comments>0</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=482a7d3a-ff62-442e-bab1-f5caab578937</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/Looking-for-projects-on-freelance-sites.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=482a7d3a-ff62-442e-bab1-f5caab578937</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=482a7d3a-ff62-442e-bab1-f5caab578937</feedburner:origLink></item>
    <item>
      <title>TypograFix 1.6 Released</title>
      <description>&lt;p&gt;&lt;img src="http://nesteruk.org/pix/0/081d9c4c-165d-4201-be39-6d42e6328c5e.jpg" align="right"/&gt;Well, you&amp;rsquo;ve guessed it, TypograFix 1.6 is out!!! There&amp;rsquo;s been lots of additions which, I&amp;rsquo;m happy to say, were driven by &lt;em&gt;need&lt;/em&gt; rather than a desire to just code something. Here is a summary of some of the things that have been implemented recently.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;p&gt;Freeform images like &lt;img src="http://nesteruk.org/pix/0/51ae96af-4af4-4f90-8c2f-3617f0d61b73.jpg"/&gt;. These images are not only generated inside the program by Direct2D, but they can also be automatically uploaded to a web server of your choice (I&amp;rsquo;m using a good old-fashioned Asp.Net web service here), so posting text rendered as images on any online resource is suddenly very easy.&lt;/p&gt;

&lt;p&gt;
  &lt;small&gt;On a small sidenote, this functionality is one of a very small number of features that I&amp;rsquo;ve made using C++ instead of C#. Deployment got a lot tougher, but the advantages are well worth it.&lt;/small&gt;
&lt;/p&gt;
&lt;/li&gt;
  &lt;li&gt;&lt;p&gt;&lt;img src="http://nesteruk.org/pix/0/9ad2d195-9ba3-48b3-837f-e2971b35e567.jpg" align="right"/&gt;Graphs. Yes, I&amp;rsquo;m only just &lt;em&gt;getting started&lt;/em&gt; with graphs here, but already I&amp;rsquo;ve got some successes, weaving a DSL into my editor and managing to produce pretty graph structures, like the one seen on the right. The only thing I have &lt;em&gt;failed&lt;/em&gt; to make (stupid me) is any support for subpixel hinting. Bizarrely, those same methods that have worked for me in the process of generating WPF images have &lt;em&gt;totally stopped working&lt;/em&gt; when using the Automated Graph Layout. Which is just sad, really.&lt;/p&gt;

&lt;/li&gt;
  &lt;li&gt;&lt;p&gt;I&amp;rsquo;ve managed to add syntax highlighting and discriminator tags for a few languages, most notably Boo. Syntax highlighting is still a pain for many reasons (none of them being my fault), but at least I&amp;rsquo;m getting to a state where this feature is universally usable.&lt;/p&gt;
&lt;/li&gt;
  &lt;li&gt;&lt;p&gt;Autoinsertion options save a lot of time. Basically, the F1&amp;mdash;F12 keys can be customized to emit strings when pressed. For example, my F2 keys emits a close-of-article mark, &lt;code&gt;&amp;amp;nbsp;■&lt;/code&gt;, in HTML. &lt;em&gt;Very&lt;/em&gt; useful.&lt;/p&gt;
&lt;/li&gt;
  &lt;li&gt;&lt;p&gt;There are some all-round UI improvements. To improve update speeds as well as mitigate potential problems, I&amp;rsquo;ve implemented caching for images, and have also added a feature where text transformation can be temporarily suspended so that 10-sec delays do not throw you off if you&amp;rsquo;re doing something important.&lt;/p&gt;
&lt;/li&gt;
  &lt;li&gt;
  &lt;p&gt;Last but not least, I&amp;rsquo;ve added support for M:tG symbols. It may not seem like much, but now I have a &lt;em&gt;very&lt;/em&gt; efficient shortcut for typing RGBWU and getting &lt;img src="http://magicnoob.com/wp-content/themes/magicnoob/images/mtg-symbols/mana_red.png"/&gt;&lt;img src="http://magicnoob.com/wp-content/themes/magicnoob/images/mtg-symbols/mana_green.png"/&gt;&lt;img src="http://magicnoob.com/wp-content/themes/magicnoob/images/mtg-symbols/mana_black.png"/&gt;&lt;img src="http://magicnoob.com/wp-content/themes/magicnoob/images/mtg-symbols/mana_white.png"/&gt;&lt;img src="http://magicnoob.com/wp-content/themes/magicnoob/images/mtg-symbols/mana_blue.png"/&gt; rendered on the page. It&amp;rsquo;s one of those little niceties when you write your own editor.&lt;/p&gt;

&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That&amp;rsquo;s all for now. As always, after any serious release, I&amp;rsquo;ll be off to test all this stuff and iron out the bugs. Rest assured, version 1.7 is already in the works.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/pNr5HgJiI7A" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/pNr5HgJiI7A/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/TypograFix-16-Released.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=5afa8252-9fce-4260-b201-7821069982bb</guid>
      <pubDate>Tue, 20 Oct 2009 20:48:00 +0300</pubDate>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=5afa8252-9fce-4260-b201-7821069982bb</pingback:target>
      <slash:comments>0</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=5afa8252-9fce-4260-b201-7821069982bb</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/TypograFix-16-Released.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=5afa8252-9fce-4260-b201-7821069982bb</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=5afa8252-9fce-4260-b201-7821069982bb</feedburner:origLink></item>
    <item>
      <title>VS2010, please, can I have a faster editor?</title>
      <description>&lt;p&gt;&lt;img src="http://www.hanselman.com/blog/content/binary/WindowsLiveWriter/VisualStudio2010Beta2_DA4D/VS_v_rgb_2.png" align="right"/&gt;I&amp;rsquo;d like to share a personal experience, if I may. I&amp;rsquo;ve been working with Visual Studio for absolute ages, since about Version 5 (which I think was called 97, but I can&amp;rsquo;t be sure). And while VS by itself was and is becoming more and more powerful with every release, I have to point out a (well-known) flaw that weighs heavily against its continuous use.&lt;/p&gt;

&lt;p&gt;
  &lt;strong&gt;Visual Studio is slow.&lt;/strong&gt;
&lt;/p&gt;

&lt;p&gt;Now, now, don&amp;rsquo;t argue. It&amp;rsquo;s unfortunate, but it&amp;rsquo;s true: beleive me, I&amp;rsquo;ve been running VS &lt;em&gt;from RAM&lt;/em&gt; and it&amp;rsquo;s still slow. What do I mean by &amp;lsquo;slow&amp;rsquo;, then? Well, the fact that when I work in SharpDevelop, things just fly. I type quickly, nothing lags, compilation is a breeze. But in VS, I feel like there&amp;rsquo;s a demon standing beside me, waiting to slap me the moment I get to any serious level of productivity.&lt;/p&gt;

&lt;p&gt;Now, the problem in VS2010 has been exacerbated, of course. 2008 is already pretty slow, especially with all the bells and whistles, but 2010 uses WPF for its UI and &amp;ndash; I don&amp;rsquo;t know, maybe it&amp;rsquo;s just me &amp;ndash; but my peception from the betas is that the extra goodness of all those nice shiny buttons is negated by the fact that I can&amp;rsquo;t get my code quickly.&lt;/p&gt;

&lt;p&gt;One can open a philosophical can of worms here about what productivity means, but my intinct tells me that the undamental goal of software development is to write good code, quickly. And for that you need&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;A text editor&lt;/li&gt;
  &lt;li&gt;A compiler&lt;/li&gt;
  &lt;li&gt;A good debugger&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If it weren&amp;rsquo;t for debugging, you can bet I&amp;rsquo;d be using other IDEs &lt;em&gt;most of the time&lt;/em&gt; because what concerns me is how fast my ideas turn to code. But regardless of it all, I am of course anxious to see VS2010 released and in action. I&amp;rsquo;m betting that potential clients would also want to see it, and not 2008, on our machines in future, and for us 2010 will be a staplemark of progress as much as anything else.&lt;/p&gt;

&lt;p&gt;We&amp;rsquo;ll just have to wait and see.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/NnsLJufUvYE" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/NnsLJufUvYE/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/VS2010-please-can-I-have-a-faster-editor.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=5b7d7fcf-a82f-4ced-bbb6-b258fd22de90</guid>
      <pubDate>Tue, 20 Oct 2009 02:02:00 +0300</pubDate>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=5b7d7fcf-a82f-4ced-bbb6-b258fd22de90</pingback:target>
      <slash:comments>5</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=5b7d7fcf-a82f-4ced-bbb6-b258fd22de90</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/VS2010-please-can-I-have-a-faster-editor.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=5b7d7fcf-a82f-4ced-bbb6-b258fd22de90</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=5b7d7fcf-a82f-4ced-bbb6-b258fd22de90</feedburner:origLink></item>
    <item>
      <title>Html encoding bugs in AntiXss</title>
      <description>&lt;p&gt;I&amp;rsquo;m annoyed. I&amp;rsquo;ve been playing with various AntiXss tools, including the one &lt;a href="http://antixss.codeplex.com"&gt;made by Microsoft&lt;/a&gt;. They all work, and they do what is expected, but they expose a fairly nasty bug. This bug is not in the Xss tools themselves, but rather in the &lt;code&gt;HttpUtility&lt;/code&gt;&amp;rsquo;s &lt;code&gt;HtmlEncode()&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;You see, it&amp;rsquo;s a bad, buggy method. It can encode an &lt;code&gt;&amp;lt;&lt;/code&gt; to become an &lt;code&gt;&amp;amp;lt;&lt;/code&gt;, but that&amp;rsquo;s about all it can do. It cannot encode something like a &amp;bull; (&lt;code&gt;&amp;amp;bull;&lt;/code&gt;), or a &amp;mdash; (&lt;code&gt;&amp;amp;mdash;&lt;/code&gt;) or a &amp;xi; (&lt;code&gt;&amp;amp;xi;&lt;/code&gt;). Why? Because it doesn&amp;rsquo;t know how.&lt;/p&gt;

&lt;p&gt;Because of this, the AntiXss methods are next to useless. What I effectively have to do is go over the resulting code &lt;em&gt;after&lt;/em&gt; the transformation has taken place, doing ridiculous stuff like &lt;code&gt;x = x.Replace("&lt;/code&gt;&amp;bull;&lt;code&gt;", "&amp;amp;bull;")&lt;/code&gt;. This is a real annoyance because I &lt;em&gt;cannot be expected&lt;/em&gt; to be able to cover every HTML entity under the sun.&lt;/p&gt;

&lt;p&gt;This goes to show a simple fact: the idea of doing AntiXss by Html-decoding everything and only encoding what you want is &lt;em&gt;fundamentally wrong&lt;/em&gt;. There has got to be a better way out there somewhere.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/Lrwjsaq8dWQ" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/Lrwjsaq8dWQ/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/Html-encoding-bugs-in-AntiXss.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=59f84b26-4d4e-48d6-87f6-8df4f6f4aa28</guid>
      <pubDate>Sat, 17 Oct 2009 02:13:00 +0300</pubDate>
      <category>c#</category>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=59f84b26-4d4e-48d6-87f6-8df4f6f4aa28</pingback:target>
      <slash:comments>2</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=59f84b26-4d4e-48d6-87f6-8df4f6f4aa28</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/Html-encoding-bugs-in-AntiXss.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=59f84b26-4d4e-48d6-87f6-8df4f6f4aa28</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=59f84b26-4d4e-48d6-87f6-8df4f6f4aa28</feedburner:origLink></item>
    <item>
      <title>A tip for managing complex CSS</title>
      <description>&lt;p&gt;
Managing a custom CSS is a nightmare, but making changes to it is even more so &amp;ndash; especially if you need to make the same change in lots of places. My solution &amp;ndash; applying T4 to CSS, thereby creating a &lt;code&gt;Site.css&lt;/code&gt; style only as a byproduct of a &lt;code&gt;Site.tt&lt;/code&gt; template:
&lt;/p&gt;
&lt;blockquote&gt;
	&lt;code&gt;&lt;font face="Consolas, Andale Mono, Courier New, Courier" size="2" color="black"&gt;&amp;lt;#@&amp;nbsp;output&amp;nbsp;extension=&lt;font color="#570000"&gt;&amp;quot;.css&amp;quot;&lt;/font&gt;&amp;nbsp;#&amp;gt;&amp;nbsp;&lt;br /&gt;
	&amp;lt;#&lt;br /&gt;
	&amp;nbsp;&amp;nbsp;&lt;font color="#0000ff"&gt;string&lt;/font&gt;&amp;nbsp;fontFamily&amp;nbsp;=&amp;nbsp;&lt;font color="#570000"&gt;&amp;quot;Calibri,&amp;nbsp;Arial,&amp;nbsp;Helvetica,&amp;nbsp;Sans-Serif&amp;quot;&lt;/font&gt;;&lt;br /&gt;
	&amp;nbsp;&amp;nbsp;&lt;font color="#0000ff"&gt;int&lt;/font&gt;&amp;nbsp;fontSize&amp;nbsp;=&amp;nbsp;12;&amp;nbsp;&lt;font color="#006400"&gt;//&amp;nbsp;px&lt;br /&gt;
	&lt;/font&gt;
	#&amp;gt;&lt;br /&gt;
	body,&amp;nbsp;p,&amp;nbsp;td,&amp;nbsp;li,&amp;nbsp;a,&amp;nbsp;input&amp;nbsp;{&amp;nbsp;&lt;strong&gt;font-family:&amp;nbsp;&amp;lt;#=&amp;nbsp;fontFamily&amp;nbsp;#&amp;gt;;&lt;/strong&gt;&amp;nbsp;}&lt;br /&gt;
	body&lt;br /&gt;
	{&lt;br /&gt;
	&amp;nbsp;&amp;nbsp;&lt;strong&gt;font-size:&amp;nbsp;&amp;lt;#=&amp;nbsp;fontSize&amp;nbsp;#&amp;gt;px;&lt;/strong&gt;&lt;br /&gt;
	&amp;nbsp;&amp;nbsp;background-color:&amp;nbsp;Black;&lt;br /&gt;
	&amp;nbsp;&amp;nbsp;color:&amp;nbsp;White;&lt;br /&gt;
	}&lt;br /&gt;
	h1,&amp;nbsp;h2&amp;nbsp;{&amp;nbsp;&lt;strong&gt;font-family:&amp;nbsp;&amp;lt;#=&amp;nbsp;fontFamily&amp;nbsp;#&amp;gt;;&lt;/strong&gt;&lt;br /&gt;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;font-weight:&amp;nbsp;normal&amp;nbsp;}&lt;br /&gt;
	&lt;/font&gt;&lt;/code&gt;
&lt;/blockquote&gt;
&lt;p&gt;
Another problem solved.
&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/cOeKiCyQuGY" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/cOeKiCyQuGY/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/A-top-for-managing-complex-CSS.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=dab2db1a-a8e6-4205-9df0-fef0a06678f0</guid>
      <pubDate>Mon, 12 Oct 2009 13:23:00 +0300</pubDate>
      <category>c#</category>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=dab2db1a-a8e6-4205-9df0-fef0a06678f0</pingback:target>
      <slash:comments>0</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=dab2db1a-a8e6-4205-9df0-fef0a06678f0</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/A-top-for-managing-complex-CSS.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=dab2db1a-a8e6-4205-9df0-fef0a06678f0</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=dab2db1a-a8e6-4205-9df0-fef0a06678f0</feedburner:origLink></item>
    <item>
      <title>Internal DSL in C# via reflection</title>
      <description>&lt;p&gt;There are many approaches to implementing user-entered DSLs. In my application, I wanted a user to enter a DSL and show its result &lt;em&gt;immediately&lt;/em&gt; (pseudo real-time) on the screen. I wanted natural text input for the creation of directed graphs with simple statements. For example, I wanted the statement &lt;code&gt;edge a b&lt;/code&gt; to create something like this:&lt;/p&gt;

&lt;p align="center"&gt;&lt;img src="http://nesteruk.org/pix/0/669c6e7c-433b-4a75-b1c5-e60322427ee3.jpg"/&gt;&lt;/p&gt;

&lt;p&gt;There are many ways of doing this, of course, but I went for something simple: using &lt;em&gt;reflection&lt;/em&gt; to transform strings into executable code. What I mean is that when someone writes &lt;code&gt;edge a b&lt;/code&gt; I really want them to call &lt;code&gt;edge("a", "b")&lt;/code&gt; in a certain class.&lt;/p&gt;

&lt;/p&gt;

&lt;blockquote&gt;&lt;code&gt;&lt;font size="2" face="Consolas, Andale Mono, Courier New, Courier" color="black"&gt;&lt;font color="#0000FF"&gt;public&lt;/font&gt;&amp;nbsp;&lt;font color="#0000FF"&gt;void&lt;/font&gt;&amp;nbsp;edge(&lt;font color="#0000FF"&gt;string&lt;/font&gt;&amp;nbsp;source,&amp;nbsp;&lt;font color="#0000FF"&gt;string&lt;/font&gt;&amp;nbsp;target)&lt;br/&gt;
{&lt;br/&gt;
&amp;nbsp;&amp;nbsp;currentEdge&amp;nbsp;=&amp;nbsp;graph.AddEdge(source,&amp;nbsp;target);&lt;br/&gt;
}&lt;br/&gt;
&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;
&lt;p&gt;With this in mind, I had to implement a simplistic parser that would find the method for me (without paying the cost of reflection). A basic &lt;code&gt;string.Split()&lt;/code&gt; got me the constituent parts and I managed to find the right method:&lt;/p&gt;

&lt;blockquote&gt;&lt;code&gt;&lt;font size="2" face="Consolas, Andale Mono, Courier New, Courier" color="black"&gt;&lt;font color="#0000FF"&gt;public&lt;/font&gt;&amp;nbsp;&lt;font color="#0000FF"&gt;void&lt;/font&gt;&amp;nbsp;AddInstruction(&lt;font color="#0000FF"&gt;string&lt;/font&gt;&amp;nbsp;line)&lt;br/&gt;
{&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&lt;font color="#0000FF"&gt;if&lt;/font&gt;&amp;nbsp;(&lt;font color="#0000FF"&gt;string&lt;/font&gt;.IsNullOrEmpty(line))&amp;nbsp;&lt;font color="#0000FF"&gt;return&lt;/font&gt;;&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&lt;font color="#0000FF"&gt;foreach&lt;/font&gt;&amp;nbsp;(Match&amp;nbsp;m&amp;nbsp;&lt;font color="#0000FF"&gt;in&lt;/font&gt;&amp;nbsp;Regex.Matches(line,&amp;nbsp;&lt;font color="#570000"&gt;"([\"'])(?:\\\\\\1|.)*?\\1"&lt;/font&gt;))&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;line&amp;nbsp;=&amp;nbsp;line.Replace(m.Value,&amp;nbsp;m.Value.Replace(&lt;font color="#570000"&gt;'&amp;nbsp;'&lt;/font&gt;,&amp;nbsp;&lt;font color="#570000"&gt;'`'&lt;/font&gt;));&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&lt;font color="#0000FF"&gt;string&lt;/font&gt;[]&amp;nbsp;parts&amp;nbsp;=&amp;nbsp;line.Split(&lt;font color="#570000"&gt;'&amp;nbsp;'&lt;/font&gt;).Select(p&amp;nbsp;=&amp;gt;&amp;nbsp;p.Replace(&lt;font color="#570000"&gt;'`'&lt;/font&gt;,&amp;nbsp;&lt;font color="#570000"&gt;'&amp;nbsp;'&lt;/font&gt;).Unquote()).ToArray();&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&lt;font color="#0000FF"&gt;if&lt;/font&gt;&amp;nbsp;(parts.Length&amp;nbsp;&amp;lt;&amp;nbsp;1)&amp;nbsp;&lt;font color="#0000FF"&gt;return&lt;/font&gt;;&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&lt;font color="#006400"&gt;//&amp;nbsp;having&amp;nbsp;acquired&amp;nbsp;the&amp;nbsp;parts,&amp;nbsp;see&amp;nbsp;if&amp;nbsp;there's&amp;nbsp;a&amp;nbsp;matching&amp;nbsp;method&lt;br/&gt;&lt;/font&gt;
&amp;nbsp;&amp;nbsp;MethodInfo&amp;nbsp;mi&amp;nbsp;=&amp;nbsp;&lt;font color="#0000FF"&gt;null&lt;/font&gt;;&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&lt;font color="#0000FF"&gt;if&lt;/font&gt;&amp;nbsp;(cachedMethodInfo.ContainsKey(&lt;font color="#0000FF"&gt;new&lt;/font&gt;&amp;nbsp;KeyValuePair&amp;lt;&lt;font color="#0000FF"&gt;string&lt;/font&gt;,&lt;font color="#0000FF"&gt;int&lt;/font&gt;&amp;gt;(parts[0],&amp;nbsp;parts.Length&amp;nbsp;-&amp;nbsp;1)))&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;mi&amp;nbsp;=&amp;nbsp;cachedMethodInfo[&lt;font color="#0000FF"&gt;new&lt;/font&gt;&amp;nbsp;KeyValuePair&amp;lt;&lt;font color="#0000FF"&gt;string&lt;/font&gt;,&amp;nbsp;&lt;font color="#0000FF"&gt;int&lt;/font&gt;&amp;gt;(parts[0],&amp;nbsp;parts.Length&amp;nbsp;-&amp;nbsp;1)];&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&lt;font color="#0000FF"&gt;else&lt;/font&gt;&lt;br/&gt;
&amp;nbsp;&amp;nbsp;{&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#0000FF"&gt;var&lt;/font&gt;&amp;nbsp;methods&amp;nbsp;=&amp;nbsp;GetType().GetMethods().Where(m&amp;nbsp;=&amp;gt;&amp;nbsp;m.Name.ToLower()&amp;nbsp;==&amp;nbsp;parts[0]&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;amp;&amp;amp;&amp;nbsp;m.GetParameters().Length&amp;nbsp;==&amp;nbsp;(parts.Length&amp;nbsp;-&amp;nbsp;1));&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#0000FF"&gt;if&lt;/font&gt;&amp;nbsp;(methods.Any())&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;mi&amp;nbsp;=&amp;nbsp;methods.First();&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cachedMethodInfo.Add(&lt;font color="#0000FF"&gt;new&lt;/font&gt;&amp;nbsp;KeyValuePair&amp;lt;&lt;font color="#0000FF"&gt;string&lt;/font&gt;,&amp;nbsp;&lt;font color="#0000FF"&gt;int&lt;/font&gt;&amp;gt;(mi.Name,&amp;nbsp;parts.Length&amp;nbsp;-&amp;nbsp;1),&amp;nbsp;mi);&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br/&gt;
&amp;nbsp;&amp;nbsp;}&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&lt;font color="#0000FF"&gt;if&lt;/font&gt;&amp;nbsp;(mi&amp;nbsp;!=&amp;nbsp;&lt;font color="#0000FF"&gt;null&lt;/font&gt;)&lt;br/&gt;
&amp;nbsp;&amp;nbsp;{&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#0000FF"&gt;var&lt;/font&gt;&amp;nbsp;pars&amp;nbsp;=&amp;nbsp;mi.GetParameters();&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#0000FF"&gt;object&lt;/font&gt;[]&amp;nbsp;ps&amp;nbsp;=&amp;nbsp;&lt;font color="#0000FF"&gt;new&lt;/font&gt;&amp;nbsp;&lt;font color="#0000FF"&gt;object&lt;/font&gt;[0];&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#0000FF"&gt;if&lt;/font&gt;&amp;nbsp;(pars.Length&amp;nbsp;==&amp;nbsp;parts.Length&amp;nbsp;-&amp;nbsp;1)&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#006400"&gt;//&amp;nbsp;try&amp;nbsp;building&amp;nbsp;a&amp;nbsp;parameter&amp;nbsp;array&lt;br/&gt;&lt;/font&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ps&amp;nbsp;=&amp;nbsp;&lt;font color="#0000FF"&gt;new&lt;/font&gt;&amp;nbsp;&lt;font color="#0000FF"&gt;object&lt;/font&gt;[pars.Length];&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#0000FF"&gt;for&lt;/font&gt;&amp;nbsp;(&lt;font color="#0000FF"&gt;int&lt;/font&gt;&amp;nbsp;i&amp;nbsp;=&amp;nbsp;0;&amp;nbsp;i&amp;nbsp;&amp;lt;&amp;nbsp;pars.Length;&amp;nbsp;i++)&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#0000FF"&gt;var&lt;/font&gt;&amp;nbsp;par&amp;nbsp;=&amp;nbsp;pars[i];&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#0000FF"&gt;var&lt;/font&gt;&amp;nbsp;source&amp;nbsp;=&amp;nbsp;parts[i&amp;nbsp;+&amp;nbsp;1];&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ps[i]&amp;nbsp;=&amp;nbsp;ConvertString(source,&amp;nbsp;par.ParameterType);&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#006400"&gt;//&amp;nbsp;parameters&amp;nbsp;ready&amp;nbsp;-&amp;nbsp;call&amp;nbsp;it&lt;br/&gt;&lt;/font&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#0000FF"&gt;try&lt;/font&gt;&amp;nbsp;{&amp;nbsp;mi.Invoke(&lt;font color="#0000FF"&gt;this&lt;/font&gt;,&amp;nbsp;ps);&amp;nbsp;}&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#0000FF"&gt;catch&lt;/font&gt;&amp;nbsp;(Exception&amp;nbsp;ex)&amp;nbsp;{&amp;nbsp;}&lt;br/&gt;
&amp;nbsp;&amp;nbsp;}&lt;br/&gt;
}&lt;br/&gt;
&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;
&lt;p&gt;You&amp;rsquo;ll notice that the &lt;code&gt;MethodInfo&lt;/code&gt; for a particular method is cached: I keep a &lt;code&gt;Dictionary&amp;lt;KeyValuePair&amp;lt;string,int&amp;gt;,MethodInfo&amp;gt;&lt;/code&gt; with the key being a pair of the method name and number of parameters.&lt;/p&gt;

&lt;p&gt;Does it work? It sure does, and the evaluations run in real-time: the graph gets re-rendered (and this is GDI+ rendering, mind you) after each keystroke. I am still polishing the details, but here&amp;rsquo;s an illustration of something more complex:&lt;/p
&lt;p align="center"&gt;&lt;img src="http://nesteruk.org/pix/0/4d247c50-5b34-4bac-acb5-a9fde35bf5bf.jpg"/&gt;&lt;/p&gt;

&lt;p&gt;As I said, this extension to my app is still in the works, but already I feel like I&amp;rsquo;ve added value to the application. All withoug concerning myself with F#, DLR, MPS and other exotic ways of implementing DSLs. All it took is some C# debugging, and here we are!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/WyW25ooIPbA" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/WyW25ooIPbA/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/Internal-DSL-in-C-via-reflection.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=8a072524-a402-44d6-acde-88af4ab74f1b</guid>
      <pubDate>Fri, 09 Oct 2009 22:02:00 +0300</pubDate>
      <category>c#</category>
      <category>dsl</category>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=8a072524-a402-44d6-acde-88af4ab74f1b</pingback:target>
      <slash:comments>0</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=8a072524-a402-44d6-acde-88af4ab74f1b</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/Internal-DSL-in-C-via-reflection.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=8a072524-a402-44d6-acde-88af4ab74f1b</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=8a072524-a402-44d6-acde-88af4ab74f1b</feedburner:origLink></item>
    <item>
      <title>Correlation of pay and benefits</title>
      <description>&lt;p&gt;One of the problems I experience when planning projects (well, not a &lt;em&gt;problem&lt;/em&gt; exactly) is this idea of applying equal rates to unequal programmers. Sure, all men and women are created equal but, as it happens, programmers are not: some are indeed better than others. This leads to a certain small issue, since customers typically think of &amp;lsquo;juniors&amp;rsquo;, &amp;lsquo;seniors&amp;rsquo; and &amp;lsquo;leads&amp;rsquo;, whereas I, being on a more humanist (or, as Spolsky says, &amp;lsquo;anthropological&amp;rsquo;) side, think of developers as, ahem, people.&lt;/p&gt;

&lt;p&gt;So why am I talking about this problem? Because I want to market services of people emphasizing that they are not good, but &lt;em&gt;brilliant&lt;/em&gt;. I mean, what&amp;rsquo;s the point of having a really kick-ass developer if their time is worth the same as someone who is just good? That&amp;rsquo;s right &amp;ndash; there is no real point.&lt;/p&gt;

&lt;p&gt;This applies to the issue of career planning: how can a person strive to &amp;lsquo;go beyond&amp;rsquo; if we are unable to support it financially? I mean sure, people can raise their own profile by participating in &lt;a href="http://ineta.ru"&gt;user&lt;/a&gt; &lt;a href="http://spbalt.net"&gt;groups&lt;/a&gt;, &lt;a href="http://platforma2009.ru"&gt;conferences&lt;/a&gt;, etc., but it&amp;rsquo;s all a bit meaningless if they can&amp;rsquo;t afford a house to live in or a car to drive.&lt;/p&gt;

&lt;p&gt;Okay, so here I go: I want to reward good developers with &lt;em&gt;money&lt;/em&gt;. The better a developer is, the more money their talent should earn the company, and the more money I want &lt;em&gt;them&lt;/em&gt; to earn. I&amp;rsquo;ve read all the postings about money being far from #1 on anyone&amp;rsquo;s priorities but, honestly, I don&amp;rsquo;t know who writes those things, and who does this research (oh, wait, I used to &lt;a href="http://mindstudies.org"&gt;do it&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Seriously, lots of companies think that infrastructural investments are the key. If you walk into a Swedish-owned company in Russia, you&amp;rsquo;ll likely see very comfortable office planning, large screens, in other words, good support for creature comforts. Yes, those are important, but some people think that&amp;rsquo;s &lt;em&gt;all&lt;/em&gt; that is important.&lt;/p&gt;

&lt;p&gt;Coming back to the issue of how to reward great people. I suppose one way is to pay them out of your profits, but that really is cheesy, because it&amp;rsquo;s &lt;em&gt;customer appreciation&lt;/em&gt; that is important. I would love people to bring in more revenue, but developers enjoy it when &lt;em&gt;customers&lt;/em&gt;, not their boss, tells them that their software is effing great. In short, two simple necessary conditions form the synergy that makes development a viable career:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;People telling you that your code is good&lt;/li&gt;
  &lt;li&gt;Progressive correlation between how good your code is and how much you earn&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The above conditions are a dream. I&amp;rsquo;ve never worked in a company where the above holds. Hopefully, it&amp;rsquo;s the kind of company I&amp;rsquo;ll manage to create.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/3uRkZx298hA" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/3uRkZx298hA/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/Correlation-of-pay-and-benefits.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=8f971697-20f1-4c59-997a-d3745feb639d</guid>
      <pubDate>Tue, 06 Oct 2009 22:11:00 +0300</pubDate>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=8f971697-20f1-4c59-997a-d3745feb639d</pingback:target>
      <slash:comments>1</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=8f971697-20f1-4c59-997a-d3745feb639d</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/Correlation-of-pay-and-benefits.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=8f971697-20f1-4c59-997a-d3745feb639d</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=8f971697-20f1-4c59-997a-d3745feb639d</feedburner:origLink></item>
    <item>
      <title>Sending a Bitmap to a web service</title>
      <description>&lt;p&gt;It turns out that &lt;code&gt;System.Drawing.Bitmap&lt;/code&gt; cannot be serialized accross the wire, which means that you need to convert it to a &lt;code&gt;byte[]&lt;/code&gt; on one end, and re-serialize on another. This is, of course, done using &lt;code&gt;MemoryStream&lt;/code&gt;, but it&amp;rsquo;s very hard to get the encoding right on the sending end, so the best bet for the web service is to use the Bitmap format:&lt;/p&gt;

&lt;blockquote&gt;&lt;code&gt;&lt;font size="2" face="Consolas, Andale Mono, Courier New, Courier" color="black"&gt;&lt;font color="#00008B"&gt;using&lt;/font&gt;&amp;nbsp;(&lt;font color="#00008B"&gt;var&lt;/font&gt;&amp;nbsp;ms&amp;nbsp;=&amp;nbsp;&lt;font color="#00008B"&gt;new&lt;/font&gt;&amp;nbsp;MemoryStream())&lt;br/&gt;
{&lt;br/&gt;
&amp;nbsp;&amp;nbsp;bmp2.Save(ms,&amp;nbsp;ImageFormat.Bmp);&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&lt;font color="#00008B"&gt;using&lt;/font&gt;&amp;nbsp;(&lt;font color="#00008B"&gt;var&lt;/font&gt;&amp;nbsp;c&amp;nbsp;=&amp;nbsp;&lt;font color="#00008B"&gt;new&lt;/font&gt;&amp;nbsp;UploadServiceSoapClient())&lt;br/&gt;
&amp;nbsp;&amp;nbsp;{&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#00008B"&gt;string&lt;/font&gt;&amp;nbsp;result&amp;nbsp;=&amp;nbsp;c.UploadImage(ms.ToArray(),&amp;nbsp;&lt;font color="#A52A2A"&gt;"secret_key"&lt;/font&gt;);&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Clipboard.SetText(result);&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;MessageBox.Show(result);&lt;br/&gt;
&amp;nbsp;&amp;nbsp;}&lt;br/&gt;
}&lt;br/&gt;
&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;
&lt;p&gt;What the above implies is that a fairly large chunk of data (width &amp;times; height &amp;times; 4) is sent accross the wire. But, on the other hand, you can write a more predictable image-saving function:&lt;/p&gt;

&lt;blockquote&gt;&lt;code&gt;&lt;font size="2" face="Consolas, Andale Mono, Courier New, Courier" color="black"&gt;&lt;font color="#00008B"&gt;using&lt;/font&gt;&amp;nbsp;(&lt;font color="#00008B"&gt;var&lt;/font&gt;&amp;nbsp;ms&amp;nbsp;=&amp;nbsp;&lt;font color="#00008B"&gt;new&lt;/font&gt;&amp;nbsp;MemoryStream(bitmapData))&lt;br/&gt;
&lt;font color="#00008B"&gt;using&lt;/font&gt;&amp;nbsp;(&lt;font color="#00008B"&gt;var&lt;/font&gt;&amp;nbsp;bmp&amp;nbsp;=&amp;nbsp;&lt;font color="#00008B"&gt;new&lt;/font&gt;&amp;nbsp;Bitmap(ms))&lt;br/&gt;
{&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&lt;font color="#006400"&gt;//&amp;nbsp;make&amp;nbsp;a&amp;nbsp;filename&amp;nbsp;and&amp;nbsp;save&lt;br/&gt;&lt;/font&gt;
&amp;nbsp;&amp;nbsp;Guid&amp;nbsp;g&amp;nbsp;=&amp;nbsp;Guid.NewGuid();&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&lt;font color="#00008B"&gt;string&lt;/font&gt;&amp;nbsp;filename&amp;nbsp;=&amp;nbsp;&lt;font color="#00008B"&gt;string&lt;/font&gt;.Format(&lt;font color="#A52A2A"&gt;@"c:\temp\{0}.jpg"&lt;/font&gt;,&amp;nbsp;g);&lt;br/&gt;
&amp;nbsp;&amp;nbsp;SaveImageAsJpeg(bmp,&amp;nbsp;filename);&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&lt;font color="#00008B"&gt;return&lt;/font&gt;&amp;nbsp;&lt;font color="#00008B"&gt;string&lt;/font&gt;.Format(&lt;font color="#A52A2A"&gt;@"http://tempuri.org/{0}.jpg"&lt;/font&gt;,&amp;nbsp;g);&lt;br/&gt;
}&lt;br/&gt;
&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;
&lt;p&gt;Anyways, I don&amp;rsquo;t know if there&amp;rsquo;s a more efficient way of doing this but, at least it works. Oh, and the encode-and-save function should make for a nice example in defensive programming:&lt;/p&gt;

&lt;blockquote&gt;&lt;code&gt;&lt;font size="2" face="Consolas, Andale Mono, Courier New, Courier" color="black"&gt;&lt;font color="#00008B"&gt;private&lt;/font&gt;&amp;nbsp;&lt;font color="#00008B"&gt;static&lt;/font&gt;&amp;nbsp;&lt;font color="#00008B"&gt;void&lt;/font&gt;&amp;nbsp;SaveImageAsJpeg(Image&amp;nbsp;bmp,&amp;nbsp;&lt;font color="#00008B"&gt;string&lt;/font&gt;&amp;nbsp;filename)&lt;br/&gt;
{&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&lt;font color="#00008B"&gt;if&lt;/font&gt;&amp;nbsp;(File.Exists(filename))&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;File.Delete(filename);&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&lt;font color="#00008B"&gt;var&lt;/font&gt;&amp;nbsp;codecs&amp;nbsp;=&amp;nbsp;ImageCodecInfo.GetImageEncoders().Where(c&amp;nbsp;=&amp;gt;&amp;nbsp;c.MimeType&amp;nbsp;==&amp;nbsp;&lt;font color="#A52A2A"&gt;"image/jpeg"&lt;/font&gt;);&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&lt;font color="#00008B"&gt;if&lt;/font&gt;&amp;nbsp;(codecs.Any())&lt;br/&gt;
&amp;nbsp;&amp;nbsp;{&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;EncoderParameters&amp;nbsp;ep&amp;nbsp;=&amp;nbsp;&lt;font color="#00008B"&gt;new&lt;/font&gt;&amp;nbsp;EncoderParameters(1);&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ep.Param[0]&amp;nbsp;=&amp;nbsp;&lt;font color="#00008B"&gt;new&lt;/font&gt;&amp;nbsp;EncoderParameter(System.Drawing.Imaging.Encoder.Quality,&amp;nbsp;100L);&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;bmp.Save(filename,&amp;nbsp;codecs.First(),&amp;nbsp;ep);&lt;br/&gt;
&amp;nbsp;&amp;nbsp;}&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&lt;font color="#00008B"&gt;else&lt;/font&gt;&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;bmp.Save(filename,&amp;nbsp;ImageFormat.Jpeg);&lt;br/&gt;
}&lt;br/&gt;
&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/SS5B3BL7Cvs" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/SS5B3BL7Cvs/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/Sending-a-Bitmap-to-a-web-service.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=67ed37e9-49ab-4e12-8af4-bcfd8bed2e12</guid>
      <pubDate>Fri, 02 Oct 2009 19:55:00 +0300</pubDate>
      <category>c#</category>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=67ed37e9-49ab-4e12-8af4-bcfd8bed2e12</pingback:target>
      <slash:comments>1</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=67ed37e9-49ab-4e12-8af4-bcfd8bed2e12</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/Sending-a-Bitmap-to-a-web-service.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=67ed37e9-49ab-4e12-8af4-bcfd8bed2e12</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=67ed37e9-49ab-4e12-8af4-bcfd8bed2e12</feedburner:origLink></item>
    <item>
      <title>The road ahead</title>
      <description>&lt;p&gt;I have spent one year working on &lt;a href="http://nesteruk.org/projects/typografix"&gt;TypograFix&lt;/a&gt;, adding little bits to the program every day, making it better and better. But now, I&amp;rsquo;m tempted to completely change the rules of the game by rewriting the application, employing a completely different strategy. Why? Because I&amp;rsquo;ve encountered a (fairly stupid) problem that I feel unable to solve with the current way of doing things.&lt;/p&gt;
&lt;h3&gt;Status Quo&lt;/h3&gt;
&lt;p&gt;Right now, TypograFix is a very powerful Html postprocessor, which turns ad-hoc HTML into something that can actually be published somewhere. I have published over 100 articles online using the system, and have fine-tuned it to the extent where it meets 99.99% of all my needs, with the extra 0.01% covered by hand-editing HTML or having to dig into the source code and changing things.&lt;/p&gt;
&lt;p&gt;So far, the program does what it is supposed to do, but it has a few flaws:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;Inefficient design&lt;/em&gt;&lt;br/&gt;Even though I have coded the program with the best practices in mind, the transformation script itself is one &lt;em&gt;massive&lt;/em&gt; &lt;code&gt;switch&lt;/code&gt; statement that goes through dozens of cases. The transformation function itself forms a kind of anti-pattern as far as programming goes, because its maintenance by someone other than me would be a nightmare.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Lack of unit tests&lt;/em&gt;&lt;br/&gt;When I started writing the program, I didn&amp;rsquo;t apply TDD. I know better now but, fact is, the transformer messes up sometimes. I have no integration tests, either, so I can&amp;rsquo;t say whether a new feature breaks old ones or not. I just hope that it doesn&amp;rsquo;t but, in reality, I&amp;rsquo;m not sure.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Lack of consistency&lt;/em&gt;&lt;br/&gt;Instead of going for the best language and framework available, I went with C# and WPF. This choice is dubious, mainly because I don&amp;rsquo;t really need WPF for such a simple UI. In fact, this application is emphatically &lt;em&gt;not&lt;/em&gt; the type that one needs the power of WPF for. Also, C# is inefficient for graphics, which led me to add C++ code to the application at a later stage just so I could get faster rendering with Direct2D and support for OpenMP and the like.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;No support for uniform format&lt;/em&gt;&lt;br/&gt;Turning HTML into HTML is just one of the many things that I need to do on a daily basis. But I seem to have failed to account for the possiblity of, say, publishing a book from the same materials.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The last point is particularly important because &amp;ndash; guess what &amp;ndash; I&amp;rsquo;m going to write a book! And, seeing how I have no intention whatsoever to use &lt;a href="http://www.docbook.org/"&gt;DocBook&lt;/a&gt; (don&amp;rsquo;t ask me why), I feel that I need to have a tool that is capable of producing both Html and, say, PDF or Word from a single source. Sounds neat, huh?&lt;/p&gt;
&lt;h3&gt;So What?&lt;/h3&gt;
&lt;p&gt;I&amp;rsquo;ve decided to make another version of TypograFix. This time, I intend to target not just the web (that&amp;rsquo;s easy, as practice indicates), but also the print medium. After all, producing nicely-made PDF documents is already a pretty good incentive, and seeing how Word isn&amp;rsquo;t up to the task (will it &lt;em&gt;ever&lt;/em&gt; support the &lt;code&gt;kern&lt;/code&gt; feature?), it might make sense to make something proprietary.&lt;/p&gt;
&lt;p&gt;So what I&amp;rsquo;m thinking of is a &lt;em&gt;structured document editor&lt;/em&gt;. The idea isn&amp;rsquo;t exactly new, but good execution is something of a rarity. Here&amp;rsquo;s what I&amp;rsquo;m thinking:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Client-server architecture&lt;/li&gt;
  &lt;li&gt;Fast, idiot-proof client (either RIA or &amp;lsquo;thick&amp;rsquo;)&lt;/li&gt;
  &lt;li&gt;Really good tech choices&amp;mdash;especially languages&lt;/li&gt;
  &lt;li&gt;A thought-out architecture&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let the fun begin!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/bhgH80XvMjc" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/bhgH80XvMjc/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/The-road-ahead.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=b234fe81-51b2-41a7-95ed-8ee860dadc95</guid>
      <pubDate>Tue, 29 Sep 2009 17:58:00 +0300</pubDate>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=b234fe81-51b2-41a7-95ed-8ee860dadc95</pingback:target>
      <slash:comments>0</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=b234fe81-51b2-41a7-95ed-8ee860dadc95</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/The-road-ahead.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=b234fe81-51b2-41a7-95ed-8ee860dadc95</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=b234fe81-51b2-41a7-95ed-8ee860dadc95</feedburner:origLink></item>
    <item>
      <title>Didactic inefficiencies</title>
      <description>&lt;p&gt;Even though I gain most of the information through the internet, I beleive that there is a fundamental problem with presenting information this way. Sure, a large proportion of content maps perfectly to text &amp;amp; image mediums, but I for one beleive that whenever you are describing some process or other, you should present it in a way that stays coherent as you move on.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a case in point. I was reading &lt;a href="http://blogs.hibernatingrhinos.com/nhibernate/archive/2008/04/10/nhibernate-and-the-unit-of-work-pattern.aspx"&gt;an article&lt;/a&gt; regarding the implementation of the &lt;em&gt;Unit of Work&lt;/em&gt; pattern with NHibernate. At some point, I realized that the code has lost its internal consistency such that things simply would not compile. This is bad because, from my perspective, it keeps me second-guessing about what the author meant at a particular instance.&lt;/p&gt;
&lt;p&gt;So here&amp;rsquo;s the deal: on the one hand, you want to present the solution in small pieces, but on the other hand, you need to offer people the possibility of viewing the whole thing. So far, this hasn&amp;rsquo;t been done well by anyone, apart from the boring &amp;lsquo;download source code&amp;rsquo; links which aren&amp;rsquo;t really helpful because by the time you unzip the stuff and open it in Visual Studio, the train of thought is lost.&lt;/p&gt;
&lt;p&gt;I beleive that software can and should overcome this problem. We already have teaching systems like &lt;a href="http://www.adobe.com/products/captivate/"&gt;Captivate&lt;/a&gt; that help us make things more interactive. If only we can somehow make it work with a program like Visual Studio, well, I think it would be really cool.&lt;/p&gt;
&lt;p&gt;Meanwhile, I&amp;rsquo;ll be thinking of how to improve TypograFix to present information better.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/bws18bptdZc" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/bws18bptdZc/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/Didactic-inefficiencies.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=2cddfe5f-0d50-400e-b42a-6aaea78f9275</guid>
      <pubDate>Sun, 27 Sep 2009 21:28:00 +0300</pubDate>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=2cddfe5f-0d50-400e-b42a-6aaea78f9275</pingback:target>
      <slash:comments>0</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=2cddfe5f-0d50-400e-b42a-6aaea78f9275</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/Didactic-inefficiencies.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=2cddfe5f-0d50-400e-b42a-6aaea78f9275</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=2cddfe5f-0d50-400e-b42a-6aaea78f9275</feedburner:origLink></item>
    <item>
      <title>More fun with C++ and DirectWrite</title>
      <description>&lt;p&gt;It may appear somewhat crazy for a .Net developer, but I&amp;rsquo;ve spent the whole of today practicing TDD with C++. My goal &amp;ndash; writing a parser that can interpret my own custom notation for OpenType and turn it into rendered text via DirectWrite.&lt;/p&gt;
&lt;p&gt;The darn thing took a whole day of my life!&lt;/p&gt;
&lt;p&gt;But, hard work and perseverence have paid off. TypograFix is now capable of understanding OT markup. What do I mean? Okay, here&amp;rsquo;s an example. Suppose I write the following:&lt;/p&gt;
&lt;pre&gt;
[30,i,sw]A[/i,sw]nother [sc,24]Day In[/sc] [Constantia,i]Paradise
&lt;/pre&gt;
&lt;p&gt;On my machine, here&amp;rsquo;s what I actually get:&lt;/p&gt;
&lt;p align="center"&gt;&lt;img src="http://nesteruk.org/blog/image.axd?picture=2009%2f9%2ffff0.jpg" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;Essentially, what I&amp;rsquo;ve made is a markup-driven rendering system that can create perfect CT/OT text. This fits nicely with my &lt;em&gt;original plan&lt;/em&gt; of adding image generation &amp;ndash; now I have two rendering methods, one for automatically replacing headings (already using it in places!) and this, the so-called &amp;lsquo;freeform&amp;rsquo; text. So far, I have added support for&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Font size &amp;amp; face&lt;/li&gt;
  &lt;li&gt;Italics &amp;amp; swash&lt;/li&gt;
  &lt;li&gt;Small capitals&lt;/li&gt;
  &lt;li&gt;Ligatures&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What&amp;rsquo;s next, then? In terms of TypograFix, I&amp;rsquo;m &lt;em&gt;very&lt;/em&gt; happy with what I have already, but I will be working on adding support for directed graphs (and no, &lt;em&gt;not&lt;/em&gt; using GraphViz), and maybe support for mind maps. If you have access to the private distribution of TypograFix, you have every reason to be excited!&lt;/p&gt;
&lt;p&gt;I might also resume work on &lt;a href="http://devtalk.net"&gt;DevTalk&lt;/a&gt;, though the complete lack of any actionwhatsoever from other project members is downright demotivating.&lt;/p&gt;&lt;/img&gt;&lt;/palign=&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/2HLtfM0wb20" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/2HLtfM0wb20/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/More-fun-with-C2b2b-and-DirectWrite.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=ca87bd0c-be98-4365-93e3-7cefd409fa3d</guid>
      <pubDate>Fri, 25 Sep 2009 23:02:00 +0300</pubDate>
      <category>c++</category>
      <category>directwrite</category>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=ca87bd0c-be98-4365-93e3-7cefd409fa3d</pingback:target>
      <slash:comments>0</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=ca87bd0c-be98-4365-93e3-7cefd409fa3d</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/More-fun-with-C2b2b-and-DirectWrite.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=ca87bd0c-be98-4365-93e3-7cefd409fa3d</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=ca87bd0c-be98-4365-93e3-7cefd409fa3d</feedburner:origLink></item>
    <item>
      <title>Block-level formatting in DirectWrite</title>
      <description>&lt;p&gt;Having figured out how to render basic text using DirectWrite, I decided to go further and try to figure out how I can apply block-level formatting to paragraphs. Amazingly, it ended up being very easy. Here&amp;rsquo;s how it goes.&lt;/p&gt;

&lt;p&gt;If you consider &lt;code&gt;IDWriteTextFormat&lt;/code&gt; to be the thing that applies basic formatting (font family, size, bold/italic/underline) to a block of text, then &lt;code&gt;IDWriteTextLayout&lt;/code&gt; is its older, much more featured cousin. This interface lets you apply block-level formatting. Specifically, what it lets you do is apply OpenType features. Let&amp;rsquo;s take a look at how it works by first creating an instance of this type:&lt;/p&gt;

&lt;blockquote&gt;&lt;code&gt;&lt;font size="2" face="Consolas, Andale Mono, Courier New, Courier" color="black"&gt;&lt;font color="#0000FF"&gt;if&lt;/font&gt;&amp;nbsp;(SUCCEEDED(hr))&lt;br/&gt;
{&lt;br/&gt;
&amp;nbsp;&amp;nbsp;hr&amp;nbsp;=&amp;nbsp;pDWriteFactory-&amp;gt;CreateTextLayout(markup,&amp;nbsp;wcslen(markup),&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pTextFormat,&amp;nbsp;width,&amp;nbsp;height,&amp;nbsp;&amp;amp;pTextLayout);&lt;br/&gt;
}&lt;br/&gt;
&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;
&lt;p&gt;You&amp;rsquo;ll notice that &lt;code&gt;TextFormat&lt;/code&gt; participates in the creation of &lt;code&gt;TextLayout&lt;/code&gt;, forming a &amp;lsquo;baseline&amp;rsquo; for subsequent manipulation. Now that we have the layout, we can also create a &lt;code&gt;Typography&lt;/code&gt; object that will let us define the total set of OT features that we want to apply:&lt;/p&gt;

&lt;blockquote&gt;&lt;code&gt;&lt;font size="2" face="Consolas, Andale Mono, Courier New, Courier" color="black"&gt;&lt;font color="#0000FF"&gt;if&lt;/font&gt;&amp;nbsp;(SUCCEEDED(hr))&lt;br/&gt;
{&lt;br/&gt;
&amp;nbsp;&amp;nbsp;pDWriteFactory-&amp;gt;CreateTypography(&amp;amp;pTypography);&lt;br/&gt;
}&lt;br/&gt;
&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;
&lt;p&gt;Having a &lt;code&gt;Typography&lt;/code&gt; object in play, we can start setting its properties, adding the OT features we want. The syntax is presented below. It does look a bit weird (especially for someone used to C#), but it works:&lt;/p&gt;

&lt;blockquote&gt;&lt;code&gt;&lt;font size="2" face="Consolas, Andale Mono, Courier New, Courier" color="black"&gt;&lt;font color="#0000FF"&gt;if&lt;/font&gt;&amp;nbsp;(SUCCEEDED(hr))&lt;br/&gt;
{&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&lt;font color="#0000FF"&gt;if&lt;/font&gt;&amp;nbsp;(smallCaps)&lt;br/&gt;
&amp;nbsp;&amp;nbsp;{&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;DWRITE_FONT_FEATURE&amp;nbsp;feature;&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;feature.nameTag&amp;nbsp;=&amp;nbsp;DWRITE_FONT_FEATURE_TAG::DWRITE_FONT_FEATURE_TAG_SMALL_CAPITALS;&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;feature.parameter&amp;nbsp;=&amp;nbsp;1;&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pTypography-&amp;gt;AddFontFeature(feature);&lt;br/&gt;
&amp;nbsp;&amp;nbsp;}&lt;br/&gt;
}&lt;br/&gt;
&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;
&lt;p&gt;Now that I have defined small-caps formatting, I need to apply it to a &lt;em&gt;range&lt;/em&gt; of characters. The range has a starting point and a character count. In the following code block, I apply it to the &lt;em&gt;whole&lt;/em&gt; paragraph:&lt;/p&gt;

&lt;blockquote&gt;&lt;code&gt;&lt;font size="2" face="Consolas, Andale Mono, Courier New, Courier" color="black"&gt;&lt;font color="#0000FF"&gt;if&lt;/font&gt;&amp;nbsp;(SUCCEEDED(hr))&lt;br/&gt;
{&lt;br/&gt;
&amp;nbsp;&amp;nbsp;DWRITE_TEXT_RANGE&amp;nbsp;range;&lt;br/&gt;
&amp;nbsp;&amp;nbsp;range.startPosition&amp;nbsp;=&amp;nbsp;0;&lt;br/&gt;
&amp;nbsp;&amp;nbsp;range.length&amp;nbsp;=&amp;nbsp;wcslen(markup);&lt;br/&gt;
&amp;nbsp;&amp;nbsp;pTextLayout-&amp;gt;SetTypography(pTypography,&amp;nbsp;range);&lt;br/&gt;
}&lt;br/&gt;
&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;
&lt;p&gt;Now, the moment of truth: we need to slightly modify the drawing statement to draw the text layout we have defined:&lt;/p&gt;

&lt;blockquote&gt;&lt;code&gt;&lt;font size="2" face="Consolas, Andale Mono, Courier New, Courier" color="black"&gt;pRT-&amp;gt;DrawTextLayout(D2D1::Point2F(),&amp;nbsp;pTextLayout,&amp;nbsp;pBlackBrush);&lt;br/&gt;
&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;
&lt;p&gt;That&amp;rsquo;s it! I bet you want to see an example! Here it is.&lt;/p&gt;

&lt;p align="center"&gt;&lt;img src="http://nesteruk.org/blog/image.axd?picture=2009%2f9%2fff0.jpg"/&gt;&lt;/p&gt;
&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/7duXLIypXhs" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/7duXLIypXhs/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/Block-level-formatting-in-DirectWrite.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=c109e12a-20b1-4b10-8c77-160fc0a0b64b</guid>
      <pubDate>Thu, 24 Sep 2009 09:55:00 +0300</pubDate>
      <category>c++</category>
      <category>directwrite</category>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=c109e12a-20b1-4b10-8c77-160fc0a0b64b</pingback:target>
      <slash:comments>0</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=c109e12a-20b1-4b10-8c77-160fc0a0b64b</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/Block-level-formatting-in-DirectWrite.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=c109e12a-20b1-4b10-8c77-160fc0a0b64b</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=c109e12a-20b1-4b10-8c77-160fc0a0b64b</feedburner:origLink></item>
    <item>
      <title>Reviewing My First Asp.Net MVC Project</title>
      <description>&lt;p&gt;I am on my way to finishing a first &amp;lsquo;proper&amp;rsquo; Asp.Net MVC project (don&amp;rsquo;t worry, it&amp;rsquo;s tiny) and I thought I&amp;rsquo;d philosophize a little bit on what went right and what went wrong.&lt;/p&gt;

&lt;p&gt;First, some context. What I wrote is basically a small group management web app &amp;ndash; something along the line of Google Groups, except that it&amp;rsquo;s a bit simpler and uses MVC. I stack was C#, Linq2Sql (don&amp;rsquo;t ask) and Sql Server 2008 as the back-end.&lt;/p&gt;

&lt;h3&gt;Syntax&lt;/h3&gt;
&lt;p&gt;If I had to start it all again, I&amp;rsquo;d pick the &lt;a href="http://dev.dejardin.org/"&gt;Spark&lt;/a&gt; view engine instead of the default WebForms one. There&amp;rsquo;s something utterly ridiculous in writing &lt;code&gt;SomeLongName sln = (SomeLongName[])ViewState["SomeLongIdentifier"]&lt;/code&gt;, and Spark is the perfect tool to avoid this. Also, the unnecessary proliferation of &lt;code&gt;&amp;lt;%= if (Some.Constant) { %&amp;gt; ... &amp;lt;% } %&amp;gt;&lt;/code&gt; clauses is downright annoying, and affects readability of code. True, Spark doesn&amp;rsquo;t &amp;lsquo;do away&amp;rsquo; with such closes (I mean the curly braces and the &lt;code&gt;#&lt;/code&gt; prefix), but at least it makes it way more neat.&lt;/p&gt;

&lt;h3&gt;Linq2Sql&lt;/h3&gt;
&lt;p&gt;I have no problems with Linq2Sql. At all. For a small site, it&amp;rsquo;s what the doctor ordered, and given the small load on the web app itself, I&amp;rsquo;ve never noticed any lag. Well, you have to bear in mind that even high-load sites such as &lt;a href="http://stackoverflow.com"&gt;StackOverflow&lt;/a&gt; use Linq2Sql, so it&amp;rsquo;s not the worst tool in the world. Personally, I consider it pretty decent, though I&amp;rsquo;m using NHibernate on things like &lt;a href="http://devtalk.net"&gt;DevTalk&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;jQuery&lt;/h3&gt;
&lt;p&gt;I didn&amp;rsquo;t know any jQuery to start with, but learning it was a breeze, and the fun stuff available as additions (e.g., &lt;a href="http://jqueryui.com"&gt;jQuery UI&lt;/a&gt; or the time picker) make it totally awesome to use when you need really good controls, fast.&lt;/p&gt;

&lt;h3&gt;Styling and Layout&lt;/h3&gt;
&lt;p&gt;I more or less messed up with respect to layout. I went with using tables instead of &lt;code&gt;div&lt;/code&gt;s for the page structure, which made things tricky on a number of levels. I mean, the site works, but it&amp;rsquo;s not easy to work with its code, because layouting is done by the table, and you have to play by the table&amp;rsquo;s rules.&lt;/p&gt;

&lt;p&gt;Also, I went through two re-styling phases, trying to get the fonts and colours to a state where they could look stylish yet project an aura of seriousness and professionalism.&lt;/p&gt;

&lt;h3&gt;Content&lt;/h3&gt;
&lt;p&gt;Made lots of mistakes regarding content. Dead/broken links, links that weren&amp;rsquo;t clear enough, content that wasn&amp;rsquo;t placed in the right spot. The only thing I did well is the administration section &amp;ndash; but that&amp;rsquo;s the part that ordinary users &lt;em&gt;do not&lt;/em&gt; see, so I was probably the only person to appreciate it.&lt;/p&gt;

&lt;p&gt;One real screw-up is that I used &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; tags for general-purpose content rather than the site name. I can already see that it has affected the site SEO-wise, and that I must revise this policy. Of course, to do this, lots of links need to be changed. I just hope that I can manage it with the &amp;lsquo;Replace In Files&amp;rsquo; feature.&lt;/p&gt;

&lt;h3&gt;Use of AOP&lt;/h3&gt;
&lt;p&gt;For some reason, instead of using filters I tried using &lt;a href="http://postsharp.org"&gt;PostSharp&lt;/a&gt; for things like authentication. It failed, and failed so miserably that I was forced to wipe out most of my aspects, pick up a book and basically &amp;lsquo;do it right&amp;rsquo;. Well, that&amp;rsquo;s another lesson learned.&lt;/p&gt;

&lt;h3&gt;Error handling&lt;/h3&gt;
&lt;p&gt;One small success is that I managed to wire up &lt;a href="http://www.codeplex.com/diagnostics"&gt;Codeplex.Diagnostics&lt;/a&gt; to the database to provide some really good feedback about error conditions. I&amp;rsquo;ve been very impressed with the framework, and now I use it with other web projects.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/nbpa0X8gGtU" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/nbpa0X8gGtU/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/Reviewing-My-First-AspNet-MVC-Project.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=47a682db-139c-4906-b660-a63a29f92e76</guid>
      <pubDate>Sun, 20 Sep 2009 14:52:00 +0300</pubDate>
      <category>asp.net</category>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=47a682db-139c-4906-b660-a63a29f92e76</pingback:target>
      <slash:comments>1</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=47a682db-139c-4906-b660-a63a29f92e76</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/Reviewing-My-First-AspNet-MVC-Project.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=47a682db-139c-4906-b660-a63a29f92e76</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=47a682db-139c-4906-b660-a63a29f92e76</feedburner:origLink></item>
    <item>
      <title>Using Direct2D and DirectWrite in .Net/C# Development</title>
      <description>&lt;p&gt;One of my personal goals is to celebrate several successes every day &amp;ndash; even if these successes are fairly small. Today, I succeeded in using the Direct2D and DirectWrite libraries from .Net! It took several hours, of course, but I managed to my .Net code to lock a bitmap and manipulate it in unmanaged C++ code, actually writing some text to the bitmap.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s how it goes. First, you need a &lt;code&gt;System.Drawing.Bitmap&lt;/code&gt; created on the .Net side. You lock its bits, then send it over to the unmanaged (&amp;lsquo;native&amp;rsquo;) function:&lt;/p&gt;

&lt;blockquote&gt;&lt;code&gt;&lt;font size="2" face="CodeFont, Consolas, Andale Mono, Courier New" color="black"&gt;&lt;font color="#0000FF"&gt;private&lt;/font&gt;&amp;nbsp;&lt;font color="#0000FF"&gt;static&lt;/font&gt;&amp;nbsp;Size&amp;nbsp;RegenerateFreeformImage(ConversionOptions&amp;nbsp;options,&amp;nbsp;&lt;font color="#0000FF"&gt;string&lt;/font&gt;&amp;nbsp;markup,&amp;nbsp;&lt;font color="#0000FF"&gt;int&lt;/font&gt;&amp;nbsp;index)&lt;br/&gt;
{&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&lt;font color="#0000FF"&gt;const&lt;/font&gt;&amp;nbsp;&lt;font color="#0000FF"&gt;int&lt;/font&gt;&amp;nbsp;w&amp;nbsp;=&amp;nbsp;512,&amp;nbsp;h&amp;nbsp;=&amp;nbsp;256;&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&lt;font color="#0000FF"&gt;using&lt;/font&gt;&amp;nbsp;(Bitmap&amp;nbsp;bmp&amp;nbsp;=&amp;nbsp;&lt;font color="#0000FF"&gt;new&lt;/font&gt;&amp;nbsp;Bitmap(w,&amp;nbsp;h))&lt;br/&gt;
&amp;nbsp;&amp;nbsp;{&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;BitmapData&amp;nbsp;data&amp;nbsp;=&amp;nbsp;bmp.LockBits(&lt;font color="#0000FF"&gt;new&lt;/font&gt;&amp;nbsp;Rectangle(0,&amp;nbsp;0,&amp;nbsp;w,&amp;nbsp;h),&amp;nbsp;ImageLockMode.ReadWrite,&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;bmp.PixelFormat);&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;NativeMethods.RenderMarkup(data.Scan0,&amp;nbsp;markup,&amp;nbsp;data.Width,&amp;nbsp;data.Height,&amp;nbsp;&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data.Stride,&amp;nbsp;options.FreeformFontFamily,&amp;nbsp;options.FreeformFontSize);&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;bmp.UnlockBits(data);&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#0000FF"&gt;string&lt;/font&gt;&amp;nbsp;filename&amp;nbsp;=&amp;nbsp;Path.Combine(Path.GetTempPath(),&amp;nbsp;options.FreeformPrefix&amp;nbsp;+&amp;nbsp;index&amp;nbsp;+&amp;nbsp;&lt;font color="#000000"&gt;".jpg"&lt;/font&gt;);&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#0000FF"&gt;using&lt;/font&gt;&amp;nbsp;(Bitmap&amp;nbsp;bmp2&amp;nbsp;=&amp;nbsp;FlowBasedRenderer.Crop(bmp))&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SaveImageAsJpeg(bmp2,&amp;nbsp;filename);&lt;br/&gt;
&amp;nbsp;&amp;nbsp;}&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&lt;font color="#0000FF"&gt;return&lt;/font&gt;&amp;nbsp;&lt;font color="#0000FF"&gt;new&lt;/font&gt;&amp;nbsp;Size(w,&amp;nbsp;h);&lt;br/&gt;
}&lt;br/&gt;
&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;
&lt;p&gt;The C++ code picks up on this with the following (rather basic) signature:&lt;/p&gt;

&lt;blockquote&gt;&lt;code&gt;&lt;font size="2" face="CodeFont, Consolas, Andale Mono, Courier New" color="black"&gt;MYAPI&amp;nbsp;&lt;font color="#0000FF"&gt;void&lt;/font&gt;&amp;nbsp;RenderMarkup(&lt;font color="#0000FF"&gt;BYTE&lt;/font&gt;*&amp;nbsp;dst,&amp;nbsp;&lt;font color="#0000FF"&gt;LPCWSTR&lt;/font&gt;&amp;nbsp;markup,&amp;nbsp;&lt;font color="#0000FF"&gt;int&lt;/font&gt;&amp;nbsp;width,&amp;nbsp;&lt;font color="#0000FF"&gt;int&lt;/font&gt;&amp;nbsp;height,&amp;nbsp;&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#0000FF"&gt;int&lt;/font&gt;&amp;nbsp;stride,&amp;nbsp;&lt;font color="#0000FF"&gt;LPCWSTR&lt;/font&gt;&amp;nbsp;fontFamily,&amp;nbsp;&lt;font color="#0000FF"&gt;float&lt;/font&gt;&amp;nbsp;fontSize)&lt;br/&gt;
{&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;#8942;&lt;br/&gt;
}&lt;br/&gt;
&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;
&lt;p&gt;Inside, all operations happen on a &lt;em&gt;separate&lt;/em&gt; bitmap object that we create, together with a render target.&lt;/p&gt;

&lt;blockquote&gt;&lt;code&gt;&lt;font size="2" face="CodeFont, Consolas, Andale Mono, Courier New" color="black"&gt;&lt;font color="#0000FF"&gt;if&lt;/font&gt;&amp;nbsp;(SUCCEEDED(hr))&lt;br/&gt;
{&lt;br/&gt;
&amp;nbsp;&amp;nbsp;hr&amp;nbsp;=&amp;nbsp;pWICFactory-&amp;gt;CreateBitmap(width,&amp;nbsp;height,&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;GUID_WICPixelFormat32bppBGR,&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;WICBitmapCacheOnLoad,&amp;nbsp;&amp;amp;pWICBitmap);&lt;br/&gt;
}&lt;br/&gt;
&lt;font color="#0000FF"&gt;if&lt;/font&gt;&amp;nbsp;(SUCCEEDED(hr))&lt;br/&gt;
{&lt;br/&gt;
&amp;nbsp;&amp;nbsp;hr&amp;nbsp;=&amp;nbsp;pD2DFactory-&amp;gt;CreateWicBitmapRenderTarget(&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pWICBitmap,&amp;nbsp;D2D1::RenderTargetProperties(),&amp;nbsp;&amp;amp;pRT);&lt;br/&gt;
}&lt;br/&gt;
&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;
&lt;p&gt;Before rendering text to the render target, some preparatory steps are needed:&lt;/p&gt;

&lt;blockquote&gt;&lt;code&gt;&lt;font size="2" face="CodeFont, Consolas, Andale Mono, Courier New" color="black"&gt;&lt;font color="#0000FF"&gt;if&lt;/font&gt;&amp;nbsp;(SUCCEEDED(hr))&lt;br/&gt;
{&lt;br/&gt;
&amp;nbsp;&amp;nbsp;hr&amp;nbsp;=&amp;nbsp;pDWriteFactory-&amp;gt;CreateTextFormat(&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;fontFamily,&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;NULL,&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;DWRITE_FONT_WEIGHT_NORMAL,&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;DWRITE_FONT_STYLE_NORMAL,&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;DWRITE_FONT_STRETCH_NORMAL,&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;fontSize,&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;L&lt;font color="#000000"&gt;""&lt;/font&gt;,&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;amp;pTextFormat);&lt;br/&gt;
}&lt;br/&gt;
&lt;font color="#0000FF"&gt;if&lt;/font&gt;&amp;nbsp;(SUCCEEDED(hr))&lt;br/&gt;
{&lt;br/&gt;
&amp;nbsp;&amp;nbsp;pTextFormat-&amp;gt;SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING);&lt;br/&gt;
&amp;nbsp;&amp;nbsp;pTextFormat-&amp;gt;SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_NEAR);&lt;br/&gt;
}&lt;br/&gt;
&lt;font color="#0000FF"&gt;if&lt;/font&gt;&amp;nbsp;(SUCCEEDED(hr))&lt;br/&gt;
{&lt;br/&gt;
&amp;nbsp;&amp;nbsp;hr&amp;nbsp;=&amp;nbsp;pRT-&amp;gt;CreateSolidColorBrush(&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;D2D1::ColorF(D2D1::ColorF::Black),&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;amp;pBlackBrush&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;);&lt;br/&gt;
}&lt;br/&gt;
&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;
&lt;p&gt;Finally, we render text to the bitmap. What&amp;rsquo;s show below is the simplest case &amp;ndash; it&amp;rsquo;s worth bearing in mind that DirectWrite can do really amazing OpenType wizardry that&amp;rsquo;s a bit too complex to show here.&lt;/p&gt;

&lt;blockquote&gt;&lt;code&gt;&lt;font size="2" face="CodeFont, Consolas, Andale Mono, Courier New" color="black"&gt;&lt;font color="#0000FF"&gt;if&lt;/font&gt;&amp;nbsp;(SUCCEEDED(hr))&lt;br/&gt;
{&lt;br/&gt;
&amp;nbsp;&amp;nbsp;pRT-&amp;gt;BeginDraw();&lt;br/&gt;
&amp;nbsp;&amp;nbsp;pRT-&amp;gt;Clear(D2D1::ColorF(D2D1::ColorF::White));&lt;br/&gt;
&amp;nbsp;&amp;nbsp;D2D1_SIZE_F&amp;nbsp;rtSize&amp;nbsp;=&amp;nbsp;pRT-&amp;gt;GetSize();&lt;br/&gt;
&amp;nbsp;&amp;nbsp;pRT-&amp;gt;DrawText(&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;markup,&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;wcslen(markup),&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pTextFormat,&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;D2D1::RectF(0,&amp;nbsp;0,&amp;nbsp;rtSize.width,&amp;nbsp;rtSize.height),&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pBlackBrush);&lt;br/&gt;
&amp;nbsp;&amp;nbsp;hr&amp;nbsp;=&amp;nbsp;pRT-&amp;gt;EndDraw();&lt;br/&gt;
}&lt;br/&gt;
&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;
&lt;p&gt;Finally, here&amp;rsquo;s something that&amp;rsquo;s amazingly easy to do: we just copy the pixels from the bitmap we rendered to to the &lt;code&gt;Bitmap&lt;/code&gt; we passed from .Net. Does it ever get more simple?&lt;/p&gt;

&lt;blockquote&gt;&lt;code&gt;&lt;font size="2" face="CodeFont, Consolas, Andale Mono, Courier New" color="black"&gt;WICRect&amp;nbsp;r;&lt;br/&gt;
r.X&amp;nbsp;=&amp;nbsp;r.Y&amp;nbsp;=&amp;nbsp;0;&lt;br/&gt;
r.Width&amp;nbsp;=&amp;nbsp;width;&lt;br/&gt;
r.Height&amp;nbsp;=&amp;nbsp;height;&lt;br/&gt;
hr&amp;nbsp;=&amp;nbsp;pWICBitmap-&amp;gt;CopyPixels(&amp;amp;r,&amp;nbsp;stride,&amp;nbsp;&lt;font color="#0000FF"&gt;sizeof&lt;/font&gt;(Pixel)&amp;nbsp;*&amp;nbsp;width&amp;nbsp;*&amp;nbsp;height,&amp;nbsp;dst);&lt;br/&gt;
&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;
&lt;p&gt;Of course, this addition was written for my &lt;a href="http://code.google.com/p/typografix"&gt;TypograFix&lt;/a&gt; pet project. Meanwhile, let me leave you with the fruits of my labour. The image below was generated using Direct2D &amp;amp; DirectWrite.&lt;/p&gt;

&lt;p align="center"&gt;&lt;img src="http://nesteruk.org/pix/11/ff0.jpg" alt="Beautiful Typography"/&gt;&lt;/p&gt;

&lt;p&gt;Ahh, can life possibly get any better?&lt;/p&gt;
&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/OMe46wJARTU" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/OMe46wJARTU/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/Using-Direct2D-and-DirectWrite-in-NetC-Development.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=b217ec4e-6696-4007-b90b-9ae8a7ba573d</guid>
      <pubDate>Mon, 14 Sep 2009 22:00:00 +0300</pubDate>
      <category>c#</category>
      <category>c++</category>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=b217ec4e-6696-4007-b90b-9ae8a7ba573d</pingback:target>
      <slash:comments>4</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=b217ec4e-6696-4007-b90b-9ae8a7ba573d</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/Using-Direct2D-and-DirectWrite-in-NetC-Development.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=b217ec4e-6696-4007-b90b-9ae8a7ba573d</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=b217ec4e-6696-4007-b90b-9ae8a7ba573d</feedburner:origLink></item>
    <item>
      <title>Community and Project News</title>
      <description>&lt;p&gt;Some more stuff about user groups: don&amp;rsquo;t know why I&amp;rsquo;m writing in English, but still&amp;hellip; first, &lt;a href="http://sp.ineta.ru"&gt;Ineta&lt;/a&gt; will now (probably) happen once a week. That&amp;rsquo;s right &amp;ndash; the idea is to meet every Friday at 6, give or take. I&amp;rsquo;m not sure what variety will be there, but the forthcoming two sessions will cover ClickOnce and SharePoint respectively. I suspect there will be more Micro Framework-related stuff to come.&lt;/p&gt;

&lt;p&gt;The second bit of fun is that we are planning a meeting on P/Invoke for the &lt;a href="http://spbalt.net"&gt;Spbalt.net&lt;/a&gt; group. We&amp;rsquo;ve got a new, cosy location (it&amp;rsquo;s got a TV instead of a projector, which is cute) that we plan to use. Should be fun.&lt;/p&gt;

&lt;p&gt;Some news about the projects I&amp;rsquo;m working on:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;p&gt;We&amp;rsquo;re almost ready to release the smart client we&amp;rsquo;re building (sort of). I think an early release is in everyone&amp;rsquo;s best interest. This project will target a huge segment of the Russian development community, so we&amp;rsquo;re a bit paranoid about quality. But I reckon we can suffer at least one non-epic fail without hitting the dirt. Ooh, I&amp;rsquo;m excited.&lt;/p&gt;
&lt;/li&gt;
  &lt;li&gt;&lt;p&gt;The &lt;a href="http://code.google.com/p/runet"&gt;other project&lt;/a&gt;, which is a web platform for developers, is slowly taking shape at &lt;a href="http://devtalk.net"&gt;http://devtalk.net&lt;/a&gt;. This project &lt;em&gt;nominally&lt;/em&gt; has about 20ish developers, so in theory you&amp;rsquo;d expect it to progress quickly. In reality, I see it going live in 2010.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Lastly: I&amp;rsquo;ve been off the grid for a while presentation-wise, but after the Spbalt.net talk I&amp;rsquo;m thinking of presenting on Ineta, seeing how it&amp;rsquo;s spinning up to be an active community again. I doubt I can do a tech-savvy intro into technology X, but some advanced stuff, like F# or Linq2Events might be kind of fun to do.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/BnCwj3Mykfw" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/BnCwj3Mykfw/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/Community-and-Project-News.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=9b46647c-b793-4fe2-b380-2bd7b972f0e7</guid>
      <pubDate>Fri, 11 Sep 2009 00:45:00 +0300</pubDate>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=9b46647c-b793-4fe2-b380-2bd7b972f0e7</pingback:target>
      <slash:comments>0</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=9b46647c-b793-4fe2-b380-2bd7b972f0e7</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/Community-and-Project-News.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=9b46647c-b793-4fe2-b380-2bd7b972f0e7</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=9b46647c-b793-4fe2-b380-2bd7b972f0e7</feedburner:origLink></item>
    <item>
      <title>Unwelcome Advice</title>
      <description>&lt;p&gt;One unpleasant side effect of representing some sort of business rather than yourself as an individual is that, suddently, a lot more people begin to lecture you (or make suggestions) regarding how software business &lt;em&gt;should&lt;/em&gt; work. It would seem that, as if by magic, many developers have just turned into specialists regarding recruiting, project management, acquisitions, etc. and have all felt a strange, inexplicable compulsion to clobber me with advice that consultants would typically give in an attempt to win some business for themselves.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Take a break, you guys!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Seriously, I don&amp;rsquo;t mind people telling me what works and what doesn&amp;rsquo;t &amp;ndash; but only if it a) comes from experience; and b) this experience is relevant to what I am doing. Failing that, everyone should just get a cup of coffee because &amp;ndash; guess what &amp;ndash; we&amp;rsquo;ve done software projects before, we&amp;rsquo;ve managed, nobody got hurt, so we&amp;rsquo;re not exactly kids who need to be educated about how the real world works. Beleive me, we know!&lt;/p&gt;

&lt;p&gt;Pseudo-expertise of the &amp;ldquo;Fowler wrote that&amp;hellip;&amp;rdquo; form is an annoying, pernicious trend that many people are substituting for real experience and real answers. If you ever feel compelled to educate some &amp;lsquo;poor misguided enterpreneur&amp;rsquo; about his &amp;lsquo;erroneous ways&amp;rsquo; in the software world, why not go into business yourself and do it the right way? This way, at least, you&amp;rsquo;ll do a lot more good &amp;ndash; both to yourself and to others.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/uwm6O23ujmc" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/uwm6O23ujmc/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/Unwelcome-Advice.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=52e0aba5-5337-4f24-8ab6-9db9fdb2f552</guid>
      <pubDate>Wed, 09 Sep 2009 22:04:00 +0300</pubDate>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=52e0aba5-5337-4f24-8ab6-9db9fdb2f552</pingback:target>
      <slash:comments>2</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=52e0aba5-5337-4f24-8ab6-9db9fdb2f552</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/Unwelcome-Advice.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=52e0aba5-5337-4f24-8ab6-9db9fdb2f552</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=52e0aba5-5337-4f24-8ab6-9db9fdb2f552</feedburner:origLink></item>
    <item>
      <title>Like Asp.Net MVC or Silverlight? We need you!</title>
      <description>&lt;p&gt;We&amp;rsquo;re building an online community for Russian-speaking developers. We need, ahem, developers in Asp.Net MVC, Silverlight, AJAX/JQuery; we also need testers, SEO people and ideologists. There&amp;rsquo;s already more than 20 members on the team. You can find the project here: &lt;a href="http://code.google.com/p/runet"&gt;http://code.google.com/p/runet&lt;/a&gt;. Contact me or leave a comment below if you want to participate.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/7Koo4YxOyv8" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/7Koo4YxOyv8/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/Like-AspNet-MVC-or-Silverlight-We-need-you!.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=ee8df52c-8145-4392-96a7-e347203bc2de</guid>
      <pubDate>Mon, 07 Sep 2009 15:32:00 +0300</pubDate>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=ee8df52c-8145-4392-96a7-e347203bc2de</pingback:target>
      <slash:comments>3</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=ee8df52c-8145-4392-96a7-e347203bc2de</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/Like-AspNet-MVC-or-Silverlight-We-need-you!.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=ee8df52c-8145-4392-96a7-e347203bc2de</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=ee8df52c-8145-4392-96a7-e347203bc2de</feedburner:origLink></item>
    <item>
      <title>TypograFix and Local Image Generation</title>
      <description>&lt;p&gt;A while back, I made a decision to add support for image generation in TypograFix. Basically, the idea is to get headings and other image elements with generated text made automatically by the program. An example can be seen &lt;a href="http://habrahabr.ru/blogs/net/68313/"&gt;here&lt;/a&gt;. So what did I learn?&lt;/p&gt;

&lt;p&gt;First, 64-bit development with Visual Studio turned out to be &lt;strong&gt;absolute hell&lt;/strong&gt;. To begin with, all the code I wrote on 32-bit Windows failed to work. It took me several hours to figure out why Visual Studio was using a 32-bit compiler with a 64-bit linker. I even had to open the Add/Remove Features window to check that 64-bit support was, in fact, installed. Also &amp;ndash; stupidly enough &amp;ndash; VS&amp;rsquo;s internal settings messed up not just the Microsoft C++ compiler, but also Intel&amp;rsquo;s one, much to my dismay.&lt;/p&gt;

&lt;p&gt;The second piece of complete nonsense was that basic use of &lt;code&gt;DllImport&lt;/code&gt; &lt;strong&gt;does not work reliably in 64-bit&lt;/strong&gt;. You end up having to do &lt;code&gt;dumpbin /exports&lt;/code&gt; and specifying the full mangled name of the function. Which is simply &lt;strong&gt;ridiculous&lt;/strong&gt;, as there seems to be no reliable alternative to doing this.&lt;/p&gt;

&lt;p&gt;But then of course everything failed due to 64-bit pointer arithmetic. I didn&amp;rsquo;t have time to check, so I stuck with slow &lt;code&gt;System.Drawing.Bitmap&lt;/code&gt;-based manipulations. They worked, and I managed to make an article (a translation of something I published on CP) with image-generated headings and comments replaced by neat inserts with Google-like rounded corners. Which is good.&lt;/p&gt;

&lt;p&gt;Oh, as for generating files, I found a really simple solution. When working locally, I put them in the temporary folder. Then, when I save the file, I also save all the images, all ready for FTP and whatnot. Yep, I do set Jpeg quality to 100% because who cares about bandwidth?&lt;/p&gt;

&lt;p&gt;TypograFix will no longer be updated on ClickOnce. I have invested far too much time into the project to offer it for free. If you can help, you&amp;rsquo;ll get a copy.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/je85JdAoHuk" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/je85JdAoHuk/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/TypograFix-and-Local-Image-Generation.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=6f86e150-eacd-43c3-a465-f24b46a5f52e</guid>
      <pubDate>Sun, 30 Aug 2009 16:29:00 +0300</pubDate>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=6f86e150-eacd-43c3-a465-f24b46a5f52e</pingback:target>
      <slash:comments>0</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=6f86e150-eacd-43c3-a465-f24b46a5f52e</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/TypograFix-and-Local-Image-Generation.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=6f86e150-eacd-43c3-a465-f24b46a5f52e</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=6f86e150-eacd-43c3-a465-f24b46a5f52e</feedburner:origLink></item>
    <item>
      <title>How to unit-test asynchronous operations?</title>
      <description>&lt;p&gt;I recently had to write unit tests for asynchronous operations &amp;ndash; specifically, files being downloaded off the internet. But how do you write a test which checks the result of an async operation? You can&amp;rsquo;t just subscribe to some &lt;code&gt;XxxCompleted&lt;/code&gt; event and do &lt;code&gt;Assert&lt;/code&gt;s there because your test runner would have exited the test method by then.&lt;/p&gt;
&lt;p&gt;The solution? Block the test method:&lt;/p&gt;
&lt;blockquote&gt;&lt;code&gt;&lt;font size="2" face="Consolas, Andale Mono, Courier New" color="black"&gt;[TestFixture]&lt;br/&gt;
&lt;font color="#00008B"&gt;public&lt;/font&gt;&amp;nbsp;&lt;font color="#00008B"&gt;class&lt;/font&gt;&amp;nbsp;MyTests&lt;br/&gt;
{&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&lt;font color="#00008B"&gt;private&lt;/font&gt;&amp;nbsp;ManualResetEvent&amp;nbsp;waitHandle;&lt;br/&gt;
&amp;nbsp;&amp;nbsp;[Test]&amp;nbsp;&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&lt;font color="#00008B"&gt;public&lt;/font&gt;&amp;nbsp;&lt;font color="#00008B"&gt;void&lt;/font&gt;&amp;nbsp;TestAsyncPageDownloading()&lt;br/&gt;
&amp;nbsp;&amp;nbsp;{&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;waitHandle&amp;nbsp;=&amp;nbsp;&lt;font color="#00008B"&gt;new&lt;/font&gt;&amp;nbsp;ManualResetEvent(&lt;font color="#00008B"&gt;false&lt;/font&gt;);&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#8942;&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;wdp.GetWebDataCompleted&amp;nbsp;+=&amp;nbsp;wdp_GetWebDataCompleted;&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;wdp.GetWebDataAsync(&lt;font color="#00008B"&gt;new&lt;/font&gt;&amp;nbsp;Uri(&lt;font color="#A52A2A"&gt;"http://nesteruk.org/blog"&lt;/font&gt;),&amp;nbsp;&lt;font color="#00008B"&gt;new&lt;/font&gt;&amp;nbsp;&lt;font color="#00008B"&gt;object&lt;/font&gt;());&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;strong&gt;waitHandle.WaitOne();&lt;/strong&gt;&amp;nbsp;&lt;font color="#006400"&gt;//&amp;nbsp;blocks&amp;nbsp;unit&amp;nbsp;tests&amp;nbsp;until&amp;nbsp;asserts&amp;nbsp;run&lt;br/&gt;&lt;/font&gt;
&amp;nbsp;&amp;nbsp;}&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&lt;font color="#00008B"&gt;void&lt;/font&gt;&amp;nbsp;wdp_GetWebDataCompleted(&lt;font color="#00008B"&gt;object&lt;/font&gt;&amp;nbsp;sender,&amp;nbsp;GetWebDataCompletedEventArgs&amp;nbsp;e)&lt;br/&gt;
&amp;nbsp;&amp;nbsp;{&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;StreamReader&amp;nbsp;sr&amp;nbsp;=&amp;nbsp;&lt;font color="#00008B"&gt;new&lt;/font&gt;&amp;nbsp;StreamReader(e.Stream);&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#00008B"&gt;string&lt;/font&gt;&amp;nbsp;s&amp;nbsp;=&amp;nbsp;sr.ReadToEnd();&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Console.WriteLine(&lt;font color="#A52A2A"&gt;"Here's&amp;nbsp;what&amp;nbsp;we&amp;nbsp;got:"&lt;/font&gt;);&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Console.WriteLine(s);&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#006400"&gt;//&amp;nbsp;the&amp;nbsp;following&amp;nbsp;assert&amp;nbsp;&lt;strong&gt;will&amp;nbsp;be&amp;nbsp;called&lt;/strong&gt;&amp;nbsp;by&amp;nbsp;the&amp;nbsp;test&amp;nbsp;runner&lt;br/&gt;&lt;/font&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Assert.Contains(s,&amp;nbsp;&lt;font color="#A52A2A"&gt;"Dmitri"&lt;/font&gt;,&amp;nbsp;&lt;font color="#A52A2A"&gt;"My&amp;nbsp;webpage&amp;nbsp;should&amp;nbsp;have&amp;nbsp;my&amp;nbsp;name."&lt;/font&gt;);&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;strong&gt;waitHandle.Set();&lt;/strong&gt;&amp;nbsp;&lt;font color="#006400"&gt;//&amp;nbsp;unblocks&amp;nbsp;unit&amp;nbsp;test&lt;br/&gt;&lt;/font&gt;
&amp;nbsp;&amp;nbsp;}&lt;br/&gt;
}&lt;br/&gt;
&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;
&lt;p&gt;Maybe there&amp;rsquo;s a better way to do this, though?&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/B25jq4HOaZ0" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/B25jq4HOaZ0/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/How-to-unit-test-asynchronous-operations.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=676e2d82-98f3-447d-92f8-37f8f82cc6ce</guid>
      <pubDate>Sun, 23 Aug 2009 16:57:00 +0300</pubDate>
      <category>c#</category>
      <category>mbunit</category>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=676e2d82-98f3-447d-92f8-37f8f82cc6ce</pingback:target>
      <slash:comments>20</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=676e2d82-98f3-447d-92f8-37f8f82cc6ce</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/How-to-unit-test-asynchronous-operations.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=676e2d82-98f3-447d-92f8-37f8f82cc6ce</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=676e2d82-98f3-447d-92f8-37f8f82cc6ce</feedburner:origLink></item>
    <item>
      <title>Making DSLs in F#</title>
      <description>&lt;ul class="Download"&gt;&lt;li&gt;&lt;a href="http://www.codeproject.com/kb/dotnet/dslfsharp/EstimationDSL.zip"&gt;Download EstimationDSL - 1.52 KB&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt; 
&lt;h2&gt;Contents&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href="#Introduction"&gt;Introduction&lt;/a&gt;&lt;/li&gt;  
  &lt;ul&gt;  
    &lt;li&gt;&lt;a href="#SourceCode"&gt;Source Code&lt;/a&gt;&lt;/li&gt;    
  &lt;/ul&gt;  
  &lt;li&gt;&lt;a href="#ProblemStatement"&gt;Problem Statement&lt;/a&gt;&lt;/li&gt;  
  &lt;ul&gt;  
    &lt;li&gt;&lt;a href="#EndUsers"&gt;End Users&lt;/a&gt;&lt;/li&gt;    
    &lt;li&gt;&lt;a href="#ContinousProcessImprovement"&gt;Continous Process Improvement&lt;/a&gt;&lt;/li&gt;    
  &lt;/ul&gt;  
  &lt;li&gt;&lt;a href="#ChoosingaLanguage"&gt;Choosing a Language&lt;/a&gt;&lt;/li&gt;  
  &lt;li&gt;&lt;a href="#FirstDSLStatement"&gt;First DSL Statement&lt;/a&gt;&lt;/li&gt;  
  &lt;li&gt;&lt;a href="#HandlingLists"&gt;Handling Lists&lt;/a&gt;&lt;/li&gt;  
  &lt;li&gt;&lt;a href="#ReferencingwithStrings"&gt;Referencing with Strings&lt;/a&gt;&lt;/li&gt;  
  &lt;li&gt;&lt;a href="#GreaterFluency"&gt;Greater Fluency&lt;/a&gt;&lt;/li&gt;  
  &lt;li&gt;&lt;a href="#GeneratingtheProject"&gt;Generating the Project&lt;/a&gt;&lt;/li&gt;  
  &lt;li&gt;&lt;a href="#Conclusion"&gt;Conclusion&lt;/a&gt;&lt;/li&gt;  
&lt;/ul&gt;
&lt;h2&gt;&lt;a name="Introduction"&gt;&lt;/a&gt;Introduction&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;re like me, you are already fed up with people throwing the term &amp;lsquo;DSL&amp;rsquo; around without showing a good example of how it&amp;rsquo;s done and where they are used &amp;ndash; not to mention giving a decent, human-readable description of DSLs that doesn&amp;rsquo;t allude to extraneous concepts (I&amp;rsquo;m talking about things like Oslo or MPS, mainly).&lt;/p&gt;
&lt;p&gt;Okay, what on Earth is a DSL? A DSL is a way of defining domain-specific (you could say industry-specific, but it can be much narrower) logic using English instead of a programming language. The obvious benefit is that non-technical people can edit the DSL, without worrying about curly braces, semicolons, that sort of thing.&lt;/p&gt;
&lt;p&gt;In this article, I&amp;rsquo;m going to show how to use the F# programming language to make a simple DSL that helps with software estimation. Just so you know, it&amp;rsquo;s a real-life example, with a more complex version of the DSL being used at our company. All right, let&amp;rsquo;s hit it!&lt;/p&gt;
&lt;p&gt;Just to say upfront, this article doesn&amp;rsquo;t present book-perfect F# code, the reason being that it doesn&amp;rsquo;t really matter since F# code is our end-product. I can think of a dozen ways to improve the F# code presented, but, as I said, that&amp;rsquo;s not the purpose of this exercise.&lt;/p&gt;
&lt;h3&gt;&lt;a name="SourceCode"&gt;&lt;/a&gt;Source Code&lt;/h3&gt;
&lt;p&gt;The attached code is a single &lt;code&gt;.fs&lt;/code&gt; file, since I would probably get flogged for posting a VS2010 solution. I hope you know what to do with it. To run it, you need to have Project 2007 installed on your machine &amp;ndash; otherwise it won&amp;rsquo;t work. Good luck!&lt;/p&gt;
&lt;h2&gt;&lt;a name="ProblemStatement"&gt;&lt;/a&gt;Problem Statement&lt;/h2&gt;
&lt;p&gt;When someone wants software written, they typically contact a software development company with something called an RFP, short for &amp;ldquo;Request for Proposal&amp;rdquo;. Depending on the level of detail of this RFP, the code shop can either do a detailed estimate or give a ballpark figure. Barring cases of clients wanting dedicated teams or having vague requirements, the estimate the code shop makes is a fixed-price project timeline. Yeah, I know it doesn&amp;rsquo;t sound particularly agile to people, but in situations where the prospective client has done lots of up-front design, it actually makes sense.&lt;/p&gt;
&lt;p&gt;Anyway, someone has to do the estimate, i.e. partition the project into tasks, give them duration, assign resources (= people) to tasks, define milestones, et cetera. This sort of estimate can be done in a program such as Microsoft Project &amp;ndash; a good choice in our case, since automating Office from an F# app is easy.&lt;/p&gt;
&lt;p&gt;So why a DSL then? Well to be honest, you can probably do an estimate at the 10&lt;sup&gt;th&lt;/sup&gt; of the time it takes to draw up the GANTT chart with all the reorderings and point-and-click mechanics of Project. Not only that, but typically you need to apply some sort of logic (i.e. use your brain, ugh!) to make sure the project plan is nice and balanced (I mean resource utilization and such). Having a DSL means you can optimize &lt;em&gt;and&lt;/em&gt; autogenerate the plan. With a DSL, you can stick as much business logic into your planning procedure as you want &amp;ndash; for example, if your company has a process database (this is CMMI Level 4-ish, btw), you could try validating the plan against empirical data.&lt;/p&gt;
&lt;p&gt;Are you sold on the DSL idea for estimates? If not, here&amp;rsquo;s another boon: integration. You can integrate Project with other systems to get more value from existing data. For example, if you run Dynamics CRM, you can tweak resource pricing for a particular client in order to put better developers on the features &lt;em&gt;they&lt;/em&gt; consider important. It all sounds very pompous and BI-ish, but that&amp;rsquo;s life of a code shop.&lt;/p&gt;
&lt;h3&gt;&lt;a name="EndUsers"&gt;&lt;/a&gt;End Users&lt;/h3&gt;
&lt;p&gt;In most code shops, barring a few exceptions, estimates are done by project managers (PMs). These guys are sometimes techies, sometimes not, so you can&amp;rsquo;t expect them to know programming. But you can certainly expect them to be able to work with a DSL and then press some magic key to generate a project plan or otherwise involve their DSL scribblings in an estimation BI scenario.&lt;/p&gt;
&lt;h3&gt;&lt;a name="ContinousProcessImprovement"&gt;&lt;/a&gt;Continous Process Improvement&lt;/h3&gt;
&lt;p&gt;At the risk of sounding cheeky, if you are constantly working on your (say) estimation DSL, improving it and tailoring it, it&amp;rsquo;s an excellent opportunity for improving your business processes. Think about it &amp;ndash; as a code shop, you can use idle dev resources to improve the efficiency of your business. Is this great, or what? I think it is, anyway.&lt;/p&gt;
&lt;h2&gt;&lt;a name="ChoosingaLanguage"&gt;&lt;/a&gt;Choosing a Language&lt;/h2&gt;
&lt;p&gt;With the problem out of the way, let&amp;rsquo;s think of a solution. You can certainly make a free-form DSL language and write a parser, but it&amp;rsquo;s kind of tedious. A simpler solution is to use a programming language which looks so English (no cultural bias here &amp;ndash; feel free to use Japanese or any other language) that the end user won&amp;rsquo;t know the difference. Of course, some language syntax &lt;em&gt;will&lt;/em&gt; creep into the DSL, but its level varies.&lt;/p&gt;
&lt;p&gt;Popular languages for DSLs include Boo (which Ayende is trying to make popular), Ruby and F#. Boo is extremely powerful, and for cases where you need metaprogramming support (&lt;em&gt;not&lt;/em&gt; our scenario), it&amp;rsquo;s fantastic. Ruby I know next to nothing about, so no comment. Now, F# is a popular language, and a first-class citizen of .Net infrastructure (as of VS2010 especially). So we&amp;rsquo;re going to look at making an infrastructure in which PMs can easily write project estimates.&lt;/p&gt;
&lt;p&gt;Let me issue a small disclaimer: being a language geared towards immutability, F# looks a bit weird when used with highly mutable concepts, such as a project which can accumulate tasks or milestones. This weirdness can be easily compensated by writing the DSL data structures in C# and then using them from F#. However, for this example, I&amp;rsquo;ll use F# excusively.&lt;/p&gt;
&lt;h2&gt;&lt;a name="FirstDSLStatement"&gt;&lt;/a&gt;First DSL Statement&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ll try to keep this simple. Let&amp;rsquo;s start by defining a project with a name and start date:&lt;/p&gt;
&lt;pre&gt;
project "Write F# DSL Article" starts_on "16/8/2009"
&lt;/pre&gt;
&lt;p&gt;The above is a completely legal F# statement. It&amp;rsquo;s basically a function call to a function called &lt;code&gt;project&lt;/code&gt; which takes 3 parameters. The first parameter is a project name &amp;ndash; no, you can&amp;rsquo;t avoid the quotes here unless you want to parse stuff yourself. The second parameter is a dummy &amp;ndash; a constant whose value is unimportant; its only purpose here is to make the spec readable and BDD-esque. You&amp;rsquo;re welcome to expand the &lt;code&gt;starts_on&lt;/code&gt; keyword into two separate parts, but I prefer not to overdo it, especially when there&amp;rsquo;s a risk of keywords creeping in. The third parameter is the project starting date as a string.&lt;/p&gt;
&lt;p&gt;Beleive it or not, the DSL uses OOP constructs in order to manage the constructed project. For example, we have a &lt;code&gt;Project&lt;/code&gt; class which is our DSL representation of a project. It&amp;rsquo;s shown below. Skipping ahead a bit, make sure your types don&amp;rsquo;t collide with other assemblies&amp;rsquo; types. After all, MS Project assemblies might just have a &lt;code&gt;Project&lt;/code&gt; type too.&lt;/p&gt;
&lt;pre&gt;
type Project() =
  [&amp;lt;DefaultValue&amp;gt;] val mutable Name : string
  [&amp;lt;DefaultValue&amp;gt;] val mutable Resources : Resource list
  [&amp;lt;DefaultValue&amp;gt;] val mutable StartDate : DateTime
  [&amp;lt;DefaultValue&amp;gt;] val mutable Groups : Group list
&lt;/pre&gt;
&lt;p&gt;I did warn about the strange syntax, did I not? The above is F#&amp;rsquo;s way of making public fields. You&amp;rsquo;ll notice also that I use &lt;code&gt;list&lt;/code&gt; types instead of the &lt;code&gt;System.Collections.Generic&lt;/code&gt; ones. It doesn&amp;rsquo;t really matter what you use for the DSL so long as it works.&lt;/p&gt;
&lt;p&gt;Our DSL will support just one project which will be at &amp;lsquo;global scope&amp;rsquo;, so to speak:&lt;/p&gt;
&lt;pre&gt;
let mutable my_project = new Project()
&lt;/pre&gt;
&lt;p&gt;The naming convention is a bit &lt;em&gt;ad hoc&lt;/em&gt; here save for the fact that, when we get to the end of the spec, we need a statement to actually do something and &lt;code&gt;my_project&lt;/code&gt; is a nice identifier name for that action. But now, we can finally show the &lt;code&gt;project&lt;/code&gt; statement from earlier.&lt;/p&gt;
&lt;pre&gt;
let project name startskey start =
  my_project &amp;lt;- new Project()
  my_project.Name &amp;lt;- name
  my_project.Resources &amp;lt;- []
  my_project.Groups &amp;lt;- []
  my_project.StartDate &amp;lt;- DateTime.Parse(start)
&lt;/pre&gt;
&lt;p&gt;There. I have probably revealed 90% of what DSL construction is like. You can close this article and go off exploring right now, since you already know how it all works. In the rest of this article, I&amp;rsquo;ll be showing a few F# implementation details.&lt;/p&gt;
&lt;h2&gt;&lt;a name="HandlingLists"&gt;&lt;/a&gt;Handling Lists&lt;/h2&gt;
&lt;p&gt;Work in projects is done by &lt;em&gt;resources&lt;/em&gt; (not very gratifying, is it?). A resource is a particular person (&amp;ldquo;John&amp;rdquo;) with a particular job title (&amp;ldquo;Junior DBA&amp;rdquo;) and a particular hourly rate ($65). A project keeps references to resources via a &lt;code&gt;Resource list&lt;/code&gt; (see, F# is human-readable). Let&amp;rsquo;s look at the definition of &lt;code&gt;Resource&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;
type Resource() =
  [&amp;lt;DefaultValue&amp;gt;] val mutable Name : string
  [&amp;lt;DefaultValue&amp;gt;] val mutable Position : string
  [&amp;lt;DefaultValue&amp;gt;] val mutable Rate : int
&lt;/pre&gt;
&lt;p&gt;I&amp;rsquo;m abusing F# once again, but at least the structure is easy to work with. Now, a resource definition is also part of our DSL, and might look as follows:&lt;/p&gt;
&lt;pre&gt;
resource "Dmitri" isa "Project Manager" with_rate 140
&lt;/pre&gt;
&lt;p&gt;The above statement employs the same trickery as &lt;code&gt;project&lt;/code&gt; except that it acts on an already-existing global variable &lt;code&gt;my_project&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;
let resource name isakey position ratekey rate =
  let r = new Resource()
  r.Name &amp;lt;- name
  r.Position &amp;lt;- position
  r.Rate &amp;lt;- rate
  my_project.Resources &amp;lt;- r :: my_project.Resources
&lt;/pre&gt;
&lt;p&gt;Resources and all other lists we use end up being listed &lt;em&gt;in reverse order&lt;/em&gt;. It&amp;rsquo;s not a problem though &amp;ndash; we reverse them when the time comes. If you don&amp;rsquo;t like it, use &lt;code&gt;List&amp;lt;T&amp;gt;&lt;/code&gt; instead.&lt;/p&gt;
&lt;h2&gt;&lt;a name="ReferencingwithStrings"&gt;&lt;/a&gt;Referencing with Strings&lt;/h2&gt;
&lt;p&gt;The next concept of our DSL I want to introduct is a &lt;em&gt;group&lt;/em&gt; of tasks. A group of tasks is typically done by one person to maintain, ahem, cognitive cohesion. We define a group as follows:&lt;/p&gt;
&lt;pre&gt;
group "Project Coordination" done_by "Dmitri"
&lt;/pre&gt;
&lt;p&gt;To put things in context, let&amp;rsquo;s look at the &lt;code&gt;Group&lt;/code&gt; class:&lt;/p&gt;
&lt;pre&gt;
type Group() =
  [&amp;lt;DefaultValue&amp;gt;] val mutable Name : string
  [&amp;lt;DefaultValue&amp;gt;] val mutable Person : Resource
  [&amp;lt;DefaultValue&amp;gt;] val mutable Tasks : Task list
&lt;/pre&gt;
&lt;p&gt;A group references a particular resource, which our DSL specifies only as a string. Problem? I don&amp;rsquo;t think so:&lt;/p&gt;
&lt;pre&gt;
let group name donebytoken resource =
  let g = new Group()
  g.Name &amp;lt;- name
  g.Person &amp;lt;- my_project.Resources |&amp;gt; List.find(fun f -&amp;gt; f.Name = resource)
  my_project.Groups &amp;lt;- g :: my_project.Groups
&lt;/pre&gt;
&lt;p&gt;Notice how, unlike with LINQ, we don&amp;rsquo;t have to call &lt;code&gt;Single()&lt;/code&gt; after searching for the right resource.&lt;/p&gt;
&lt;h2&gt;&lt;a name="GreaterFluency"&gt;&lt;/a&gt;Greater Fluency&lt;/h2&gt;
&lt;p&gt;Last but not least, we define tasks. Now, isn&amp;rsquo;t it great when you can say, for example, the following:&lt;/p&gt;
&lt;pre&gt;
task "PayPal Integration" takes 2 weeks
&lt;/pre&gt;
&lt;p&gt;In fact, you can. This type of fluency is achieved by judiciously defining timespan constants so that their values are &lt;em&gt;meaningful&lt;/em&gt;. For example,&lt;/p&gt;
&lt;pre&gt;
let hours = 1
let hour = 1
let days = 2
let day = 2
let weeks = 3
let week = 3
let months = 4
let month = 4
&lt;/pre&gt;
&lt;p&gt;The values do not matter so long as they are distinct. Now we can define a task&amp;hellip;&lt;/p&gt;
&lt;pre&gt;
type Task() =
  [&amp;lt;DefaultValue&amp;gt;] val mutable Name : string
  [&amp;lt;DefaultValue&amp;gt;] val mutable Duration : string
&lt;/pre&gt;
&lt;p&gt;&amp;hellip; and add it to the project:&lt;/p&gt;
&lt;pre&gt;
let task name takestoken count timeunit =
  let t = new Task()
  t.Name &amp;lt;- name
  let dummy = 1 + count
  match timeunit with
  | 1 -&amp;gt; t.Duration &amp;lt;- String.Format("{0}h", count)
  | 2 -&amp;gt; t.Duration &amp;lt;- String.Format("{0}d", count)
  | 3 -&amp;gt; t.Duration &amp;lt;- String.Format("{0}wk", count)
  | 4 -&amp;gt; t.Duration &amp;lt;- String.Format("{0}mon", count)
  | _ -&amp;gt; raise(ArgumentException("only spans of hour(s), day(s), week(s) and month(s) are supported"))
  let g = List.hd my_project.Groups
  g.Tasks &amp;lt;- t :: g.Tasks
&lt;/pre&gt;
&lt;p&gt;Notice that for each timespan I slightly change the way the duration is phrased so that Project is capable of eating the spec. The dummy expression above tells F# that &lt;code&gt;count&lt;/code&gt; is an integer &amp;ndash; I could have defined it explicitly, of course, but I&amp;rsquo;m just too lazy. Oh, by the way, notice how easy it is for us to find the &lt;em&gt;current&lt;/em&gt; (i.e., last) task. Because we&amp;rsquo;re using F#, this task is actually &lt;em&gt;first&lt;/em&gt; in the list, so we can just call &lt;code&gt;List.hd&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;&lt;a name="GeneratingtheProject"&gt;&lt;/a&gt;Generating the Project&lt;/h2&gt;
&lt;p&gt;We&amp;rsquo;ve got &lt;em&gt;everything&lt;/em&gt; and are ready to generate the project. The following (somewhat cheesy) command does it:&lt;/p&gt;
&lt;pre&gt;
prepare my_project
&lt;/pre&gt;
&lt;p&gt;Now, I&amp;rsquo;m about to show you the &lt;em&gt;whole&lt;/em&gt; &lt;code&gt;prepare&lt;/code&gt; definition, which uses the Project API to make the, umm, project. Notice how succint F# is:&lt;/p&gt;
&lt;pre&gt;
let prepare (proj:Project) =
  let app = new ApplicationClass()
  app.Visible &amp;lt;- true
  let p = app.Projects.Add()
  p.Name &amp;lt;- proj.Name
  proj.Resources |&amp;gt; List.iter(fun r -&amp;gt;
    let r' = p.Resources.Add()
    r'.Name &amp;lt;- r.Position // position, not name :)
    let tables = r'.CostRateTables
    let table = tables.[1]
    table.PayRates.[1].StandardRate &amp;lt;- r.Rate
    table.PayRates.[1].OvertimeRate &amp;lt;- (r.Rate + (r.Rate &amp;gt;&amp;gt;&amp;gt; 1)))
  // make root task with project name
  let root = p.Tasks.Add()
  root.Name &amp;lt;- proj.Name
  // add groups
  proj.Groups |&amp;gt; List.rev |&amp;gt; List.iter(fun g -&amp;gt; 
    let t = p.Tasks.Add()
    t.Name &amp;lt;- g.Name
    t.OutlineLevel &amp;lt;- 2s
    // who is responsible for this group?
    t.ResourceNames &amp;lt;- g.Person.Position
    // add tasks
    let tasksInOrder = g.Tasks |&amp;gt; List.rev
    tasksInOrder |&amp;gt; List.iter(fun t' -&amp;gt;
        let t'' = p.Tasks.Add(t'.Name)
        t''.Duration &amp;lt;- t'.Duration
        t''.OutlineLevel &amp;lt;- 3s
        // make task follow previous
        let idx = tasksInOrder |&amp;gt; List.findIndex(fun f -&amp;gt; f.Equals(t'))
        if (idx &amp;gt; 0) then 
          t''.Predecessors &amp;lt;- Convert.ToString(t''.Index - 1)
      )
    )
&lt;/pre&gt;
&lt;p&gt;Yep, we finally reverse those backward lists with &lt;code&gt;List.rev&lt;/code&gt; &amp;ndash; probably not the fastest operation in the world, but I don&amp;rsquo;t care. All that matters is that the script runs and gives us the results we want &amp;ndash; resource definitions, group names and tasks which are grouped and linked. What more could a PM ask for? (Quite a bit actually, but that&amp;rsquo;s another story.)&lt;/p&gt;
&lt;p&gt;A complete project definition can therefore look like this:&lt;/p&gt;
&lt;pre&gt;
project "F# DSL Article" starts "01/01/2009"
resource "Dmitri" isa "Writer" with_rate 140
resource "Computer" isa "Dumb Machine" with_rate 0
group "DSL Popularization" done_by "Dmitri"
task "Create basic estimation DSL" takes 1 day
task "Write article" takes 1 day
task "Post article and wait for comments" takes 1 week
group "Infrastructure Support" done_by "Computer"
task "Provide VS2010 and MS Project" takes 1 day
task "Download and deploy TypograFix" takes 1 day
task "Sit idly while owner waits for comments" takes 1 week
prepare my_project
&lt;/pre&gt;
&lt;h2&gt;&lt;a name="Conclusion"&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;This article shows that making a DSL in F# is really simple. Of course, the thing about DSLs is they are &lt;em&gt;domain-specific&lt;/em&gt;, so for the domain &lt;em&gt;you&lt;/em&gt; choose you might encounter a lot more challenges. Have fun!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/AHR8BtgUx60" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/AHR8BtgUx60/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/Making-DSLs-in-F.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=906a9b11-1a0a-4a24-ab4d-f6eda1cd947c</guid>
      <pubDate>Mon, 17 Aug 2009 08:54:00 +0300</pubDate>
      <category>dsl</category>
      <category>f#</category>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=906a9b11-1a0a-4a24-ab4d-f6eda1cd947c</pingback:target>
      <slash:comments>1</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=906a9b11-1a0a-4a24-ab4d-f6eda1cd947c</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/Making-DSLs-in-F.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=906a9b11-1a0a-4a24-ab4d-f6eda1cd947c</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=906a9b11-1a0a-4a24-ab4d-f6eda1cd947c</feedburner:origLink></item>
    <item>
      <title>Windows 2008 R2 out on MSDN!</title>
      <description>&lt;p&gt;People talk about the release of Windows 7 but, IMHO, today&amp;rsquo;s release of Windows 2008 R2 on MSDN is more important. Why? Because I beleive developers should have a Server version of Windows installed on their machines. After all, you learn whatever version of Windows you use, and the Server variety is a lot more complex &amp;ndash; so you&amp;rsquo;ll be picking up important new skills that help with enterprise development.&lt;/p&gt;
&lt;p&gt;I am downloading the DVD image as I write this. Care to guess what software I&amp;rsquo;m going to install?&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/zH8aXBC-sNI" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/zH8aXBC-sNI/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/Windows-2008-R2-out-on-MSDN!.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=558f3214-61d5-40af-ae07-b39dbd7c8742</guid>
      <pubDate>Fri, 14 Aug 2009 23:48:00 +0300</pubDate>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=558f3214-61d5-40af-ae07-b39dbd7c8742</pingback:target>
      <slash:comments>0</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=558f3214-61d5-40af-ae07-b39dbd7c8742</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/Windows-2008-R2-out-on-MSDN!.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=558f3214-61d5-40af-ae07-b39dbd7c8742</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=558f3214-61d5-40af-ae07-b39dbd7c8742</feedburner:origLink></item>
    <item>
      <title>Late-night musings on Russian Outsourcing</title>
      <description>&lt;p&gt;It&amp;rsquo;s no secret that the wheels of software outsourcing here in Russia have either ground to a halt or have significantly slowed down. It&amp;rsquo;s not exactly surprising, seeing how most profitable, well-funded code shops were developing software either for financial institutions or for companies whose well-being would be affected (sometimes rather dramatically) by the demise or restructuring of said insitutions. Such as start-ups, for example.&lt;/p&gt;
&lt;p&gt;So what&amp;rsquo;s happening exactly? Well, those outsourcers who didn&amp;rsquo;t get bankrupted (and some ODCs &lt;em&gt;did&lt;/em&gt; get closed down, such as Saxo Bank&amp;rsquo;s, for instance) have certainly lost their share, have made job cuts and are now sitting it out while waiting for business to return. On the other hand, new companies (such as &lt;a href="http://activemesa.com"&gt;mine&lt;/a&gt;) are springing up all the time, eager to retake the business from the big players as soon as it arises. And why not? The crisis has certainly leveled the playing field, and people&amp;rsquo;s strategies for attracting new business have changed as a result.&lt;/p&gt;
&lt;p&gt;My approach to all of this is two-pronged. On the other hand, we have to be ready to pounce on practically any order that comes out, even if the rates aren&amp;rsquo;t in our favor (I sometimes wonder why Russian outsourcing exists at all, when freelance sites teem with $15/hour coders), even if we don&amp;rsquo;t particularly fancy a particular client. Now&amp;rsquo;s not the time to be picky. Which is why the 2&lt;sup&gt;nd&lt;/sup&gt; avenue of escape from this crisis is taking on &lt;em&gt;internal&lt;/em&gt; (i.e., Russian) customers. This is even more challenging, and leads to two problems: the first being that you can&amp;rsquo;t just attract Russian business without connections (especially government contracts), and the second being that you probably can&amp;rsquo;t charge the same rates as you charge your Western partners unless you net someone like Gazprom (which is challenging due to part 1 of this argument).&lt;/p&gt;
&lt;p&gt;There must be a select few companies on this planet who make really great software and who charge really decent rates for it. And I bet they&amp;rsquo;re keeping their secrets very well, let everyone in jump on their bandwagon.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/lxfaQiqwCEE" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/lxfaQiqwCEE/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/Late-night-musings-on-Russian-Outsourcing.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=f7068d36-fc4b-4903-bdc9-fd55d57825bb</guid>
      <pubDate>Tue, 11 Aug 2009 00:51:00 +0300</pubDate>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=f7068d36-fc4b-4903-bdc9-fd55d57825bb</pingback:target>
      <slash:comments>0</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=f7068d36-fc4b-4903-bdc9-fd55d57825bb</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/Late-night-musings-on-Russian-Outsourcing.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=f7068d36-fc4b-4903-bdc9-fd55d57825bb</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=f7068d36-fc4b-4903-bdc9-fd55d57825bb</feedburner:origLink></item>
    <item>
      <title>Beware of C-style macros in Boo</title>
      <description>&lt;p&gt;It is strange that the term &lt;em&gt;macro&lt;/em&gt; is used to denote the chief metaprogramming facility in .Net. After all, macros in C++ are a lot weaker &amp;ndash; they cannot manipulate the AST, in fact, they cannot even manipulate code internally or do compile-time evaluation.&lt;/p&gt;
&lt;p&gt;Indeed we, as developers, can use the macro facilities in languages such as Boo in order to produce C-style macros. For example, here&amp;rsquo;s how one would instrument a Boo repetition macro in C style:&lt;/p&gt;
&lt;blockquote&gt;&lt;code&gt;&lt;font size="2" face="Consolas, Andale Mono, Courier New" color="black"&gt;macro&amp;nbsp;RepeatCStyle(c&amp;nbsp;&lt;font color="#00008B"&gt;as&lt;/font&gt;&amp;nbsp;&lt;font color="#00008B"&gt;int&lt;/font&gt;):&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&lt;font color="#00008B"&gt;return&lt;/font&gt;&amp;nbsp;[|&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#00008B"&gt;for&lt;/font&gt;&amp;nbsp;i&amp;nbsp;&lt;font color="#00008B"&gt;in&lt;/font&gt;&amp;nbsp;range($c):&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$(RepeatCStyle.Body)&lt;br/&gt;
&amp;nbsp;&amp;nbsp;|]&lt;br/&gt;
&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;
&lt;p&gt;This macro simply serves as a syntactic shortcut, which means that if you call it with&lt;/p&gt;
&lt;blockquote&gt;&lt;code&gt;&lt;font size="2" face="Consolas, Andale Mono, Courier New" color="black"&gt;RepeatXxx&amp;nbsp;3:&lt;br/&gt;
&amp;nbsp;&amp;nbsp;print&amp;nbsp;&lt;font color="#A52A2A"&gt;"Go"&lt;/font&gt;&lt;br/&gt;
&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;
&lt;p&gt;you&amp;rsquo;ll basically get the following C# code:&lt;/p&gt;
&lt;blockquote&gt;&lt;code&gt;&lt;font size="2" face="Consolas, Andale Mono, Courier New" color="black"&gt;&lt;font color="#00008B"&gt;int&lt;/font&gt;&amp;nbsp;___temp14&amp;nbsp;=&amp;nbsp;0;&lt;br/&gt;
&lt;font color="#00008B"&gt;while&lt;/font&gt;&amp;nbsp;(___temp14&amp;nbsp;&amp;lt;&amp;nbsp;3)&lt;br/&gt;
{&lt;br/&gt;
&amp;nbsp;&amp;nbsp;&lt;font color="#00008B"&gt;int&lt;/font&gt;&amp;nbsp;i&amp;nbsp;=&amp;nbsp;___temp14;&lt;br/&gt;
&amp;nbsp;&amp;nbsp;___temp14++;&lt;br/&gt;
&amp;nbsp;&amp;nbsp;Console.WriteLine(&lt;font color="#A52A2A"&gt;"Go"&lt;/font&gt;);&lt;br/&gt;
}&lt;br/&gt;
&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;
&lt;p&gt;You could have used an ordinary helper function in this case. The beauty of macros is in compile-time evaluation and effective inlining of code. Consider the following macro:&lt;/p&gt;
&lt;blockquote&gt;&lt;code&gt;&lt;font size="2" face="Consolas, Andale Mono, Courier New" color="black"&gt;macro&amp;nbsp;RepeatInline(c&amp;nbsp;&lt;font color="#00008B"&gt;as&lt;/font&gt;&amp;nbsp;&lt;font color="#00008B"&gt;int&lt;/font&gt;):&lt;br/&gt;
&amp;nbsp;&amp;nbsp;body&amp;nbsp;=&amp;nbsp;RepeatInline.Body&lt;br/&gt;
&amp;nbsp;&amp;nbsp;yieldAll&amp;nbsp;body&amp;nbsp;&lt;font color="#00008B"&gt;for&lt;/font&gt;&amp;nbsp;i&amp;nbsp;&lt;font color="#00008B"&gt;in&lt;/font&gt;&amp;nbsp;range(c)&lt;br/&gt;
&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;
&lt;p&gt;This macro is more interesting because it effectively returns three copies of the same statement as an &lt;code&gt;IEnumerable&lt;/code&gt;. The end-result is the following C# equivalent:&lt;/p&gt;
&lt;blockquote&gt;&lt;code&gt;&lt;font size="2" face="Consolas, Andale Mono, Courier New" color="black"&gt;Console.WriteLine(&lt;font color="#A52A2A"&gt;"Go"&lt;/font&gt;);&lt;br/&gt;
Console.WriteLine(&lt;font color="#A52A2A"&gt;"Go"&lt;/font&gt;);&lt;br/&gt;
Console.WriteLine(&lt;font color="#A52A2A"&gt;"Go"&lt;/font&gt;);&lt;br/&gt;
&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;
&lt;p&gt;This is certainly much closer to the macros&amp;rsquo; purpose as a metaprogramming tool.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/JHIcGu8blOc" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/JHIcGu8blOc/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/Beware-of-C-style-macros-in-Boo.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=688ce838-d599-4ed5-97f4-59f48a7b5cf2</guid>
      <pubDate>Thu, 09 Jul 2009 12:50:00 +0300</pubDate>
      <category>boo</category>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=688ce838-d599-4ed5-97f4-59f48a7b5cf2</pingback:target>
      <slash:comments>18</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=688ce838-d599-4ed5-97f4-59f48a7b5cf2</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/Beware-of-C-style-macros-in-Boo.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=688ce838-d599-4ed5-97f4-59f48a7b5cf2</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=688ce838-d599-4ed5-97f4-59f48a7b5cf2</feedburner:origLink></item>
    <item>
      <title>TypograFix Improvements</title>
      <description>&lt;p&gt;My pet project, &lt;a href="http://code.google.com/p/typografix"&gt;TypograFix&lt;/a&gt;, is about a year old (I could be wrong), and it seems that most issues regarding text transforms have been ironed out precisely to the extent where I can produce HTML that is perfect or near-perfect. Now that the bulk of the work is over, I&amp;rsquo;m thinking of adding some of the more exotic (and difficult to do) features, including:&lt;/p&gt;
&lt;ol style="list-style-type:cjk-ideographic"&gt;
  &lt;li&gt;&lt;p&gt;&lt;strong&gt;Server-side image generation&lt;/strong&gt; &amp;mdash; This is a very vague objective but, at the very least, I should have the possibility to generate, e.g., a histogram or a nice heading just by typing text. It&amp;rsquo;s completely feasible, though of course this feature requires &lt;code&gt;IsolatedStorage&lt;/code&gt; on the client side, and image hosting whenever the article is posted. This is annoying, because we would need to specify the URL or the target folder (i.e., in the app itself you&amp;rsquo;d have a field called &lt;code&gt;Image Url&lt;/code&gt; which would contain something like &lt;code&gt;http://nesteruk.org/images/&lt;/code&gt;, to which the filenames are appended.) One other potential feature is the generation of &lt;a href="http://blogs.gotdotnet.ru/personal/nesteruk/PermaLink.aspx?guid=cfb5a54f-0df7-47e2-a921-afadbe025bdc"&gt;graphs&lt;/a&gt; and such.&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;&lt;p&gt;&lt;strong&gt;Better code highlighting&lt;/strong&gt; &amp;mdash; seeing how one cannot use CSS on most publis resources, most syntax highlighting is done in very strange ways, using &lt;code&gt;&amp;lt;blockquote&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;code&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;font&amp;gt;&lt;/code&gt; tags. Current customizations inside code blocks are already very rich, though, with support for colours, italic comments, and the like. But I think that more can be done: after all, we&amp;rsquo;re allowed to use the &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tag in code, so perhaps we can somehow make text more readable? In actual fact, the current use of the &lt;code&gt;&amp;lt;code&amp;gt;&lt;/code&gt; tag is dubious, because the tag offers &lt;em&gt;no value&lt;/em&gt; when formatting. A new formatting script for code &amp;ndash; if I ever bother to write one &amp;ndash; will probably be written in F#.&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;&lt;p&gt;&lt;strong&gt;Stylesheet management&lt;/strong&gt; &amp;mdash; this is important because, although I&amp;rsquo;ve added some spurious stylesheet-related tabs, it&amp;rsquo;s not very user-friendly. It would be better to have a manager that could habdle stylesheets and &amp;ndash; possibly &amp;ndash; even program settings in a way where one could switch from one site&amp;rsquo;s formatting rules to another&amp;rsquo;s. Once again, this is a fairly difficult thing to implement correctly.&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;&lt;p&gt;&lt;strong&gt;Custom rules&lt;/strong&gt; &amp;mdash; if there&amp;rsquo;s anything I&amp;rsquo;ve learned while publishing online, it&amp;rsquo;s that ever website or blog system has its own set of mess-ups and blatant developer mistakes, and no matter how good TypograFix is, most systems have flaws that have to be havigated around by hand[&lt;a href="#Reference1" title="The only exception from this rule is the BlogEngine.net blogging platform which I use." name="BackReference1"&gt;1&lt;/a&gt;]. Some of these weird features have already made their way into the program &amp;ndash; e.g., the option to add blank lines after &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; tags. Having it all in a more manageable fashion would be nice.&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;&lt;p&gt;&lt;strong&gt;Fun with Unicode&lt;/strong&gt; &amp;mdash; there are lots of characters in the Unicode character set that can be abused to make all sorts of strange images and the like. For example, one can emulate Japanese list numbering by using Unicode characters, and then provide an option to repaginate lists using paragraphs prefixed by those glyphs. Actually, what would be good to start with is a fast, JavaScript-driven Unicode browser.&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;&lt;p&gt;&lt;strong&gt;Smarter Cut &amp;amp; Paste&lt;/strong&gt; &amp;mdash; right now, HTML copied off a website gets pasted as plain-text. It would be nice if the program could interoperate with HTML and maybe even RTF/Word clipboard formats in order to preserve at least some typographic information about the data being pasted in. Also &amp;ndash; and this would be really good &amp;ndash; I think that Excel importing and pasting in Excel or CSV-formatted data should also be processed correctly.&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;&lt;p&gt;&lt;strong&gt;Print production&lt;/strong&gt; &amp;mdash; seeing how TypograFix is good for preparing technical documentation, maybe there is a way to prepare text in a format best suited for importing into InDesign. Of course, text has to be imported without any styles, but at least we can preserve the basic structure (e.g., line breaks) so that it doesn&amp;rsquo;t have to be redone.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This is a very rough list, but I imagine that I will me making a start on some of these features pretty soon.&lt;/p&gt;
&lt;p&gt;Notes&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;&lt;a name="Reference1"&gt;&lt;/a&gt;&lt;a href="#BackReference1" title="Back to text"&gt;&amp;uarr;&lt;/a&gt; The only exception from this rule is the BlogEngine.net blogging platform which I use.&lt;/li&gt;
&lt;/ol&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/KgQ2QdiV-os" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/KgQ2QdiV-os/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/TypograFix-Improvements.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=502a760c-ecc2-462e-863e-15e2a1bfcea7</guid>
      <pubDate>Tue, 07 Jul 2009 13:36:00 +0300</pubDate>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=502a760c-ecc2-462e-863e-15e2a1bfcea7</pingback:target>
      <slash:comments>43</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=502a760c-ecc2-462e-863e-15e2a1bfcea7</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/TypograFix-Improvements.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=502a760c-ecc2-462e-863e-15e2a1bfcea7</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=502a760c-ecc2-462e-863e-15e2a1bfcea7</feedburner:origLink></item>
    <item>
      <title>Working with pure C# auto-properties</title>
      <description>&lt;p&gt;
Trying to follow your own advice is something that only sounds easy. The case in point: ubiquitous use of auto-properties. The idea sounds nice, but it doesn&amp;#39;t quite work.
&lt;/p&gt;
&lt;pre&gt;
public class C
{
public IList MySomethings { get; set; }
}
&lt;/pre&gt;
&lt;p&gt;
Having lots of lists in a class is tough: each &lt;code&gt;IList&lt;/code&gt; deserves its own &lt;code&gt;List&lt;/code&gt; initialization. In an ideal world, you could do the following:
&lt;/p&gt;
&lt;pre&gt;
public class C
{
[Dependency]
public IList MySomethings { get; set; }
}
// and then
var uc = new UnityContainer();
uc.RegisterType, List&amp;gt;();
&lt;/pre&gt;
&lt;p&gt;
But we cannot do it. So, aside from the option of creating everything manually (ugh) and using Nemerle (I&amp;#39;m &lt;em&gt;almost&lt;/em&gt; there), the only way to init those stupid lists manually (I have many) is to write the following:
&lt;/p&gt;
&lt;pre&gt;
public class C
{
[LazyLoad(typeof(List))]
public IList MySomethings; // it&amp;#39;s a field!
}
&lt;/pre&gt;
&lt;p&gt;
Using a PostSharp aspect certainly might do the trick, but it&amp;#39;s only simple if it&amp;#39;s a field. Nonetheless, since fields can be rewritten by PostSharp into properties, we might get the semantics similar to the following:
&lt;/p&gt;
&lt;pre&gt;
public class C
{
private IList mySomethings;
public IList MySomethings
{
get { return mySomethings ?? (mySomethings = new List(); }
// where is the set? :)
}
}
&lt;/pre&gt;
&lt;p&gt;
This bit of metaprogramming is naughty: we have a &lt;code&gt;set&lt;/code&gt;-less property in place of a field. It&amp;#39;s lazy-loaded so none of that &lt;code&gt;null&lt;/code&gt; nonsense.
&lt;/p&gt;
&lt;p&gt;
This solution can even be done without AOP. It works, and is moderately readable (I hope everyone recognizes the ?? operator). It&amp;#39;s not very elegant in the sense where I might want to init this stuff from a container but then again, in my case all I need are empty lists. As a future task, I&amp;#39;ll investigate Nemerle for a simpler, DSL=like way of defining these structures.
&lt;/p&gt;
&lt;p&gt;
On a happy note: I found some code that used &lt;code&gt;INotifyPropertyChanged&lt;/code&gt; and refactored it, removing any mention of that interface completely. AOP rules!
&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/k6SpdqFOg6c" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/k6SpdqFOg6c/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/Working-with-pure-C-auto-properties.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=b04b9584-d270-4cc8-ac1e-5902398c96ba</guid>
      <pubDate>Sat, 04 Jul 2009 00:20:00 +0300</pubDate>
      <category>c#</category>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=b04b9584-d270-4cc8-ac1e-5902398c96ba</pingback:target>
      <slash:comments>16</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=b04b9584-d270-4cc8-ac1e-5902398c96ba</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/Working-with-pure-C-auto-properties.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=b04b9584-d270-4cc8-ac1e-5902398c96ba</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=b04b9584-d270-4cc8-ac1e-5902398c96ba</feedburner:origLink></item>
    <item>
      <title>Promotion of engineering culture</title>
      <description>&lt;p&gt;Seeing how I&amp;rsquo;m constantly looking for ways to promote .Net and software development in general, I&amp;rsquo;ve been thinking about ways in which the .Net community can be galvanized into action &amp;ndash; i.e., how can people be motivated to write articles, post blog entries, meet in professional conferences, host worshops, et cetera? Putting this in the context of the city I live, it would appear that what I&amp;rsquo;m trying to achieve is impossible.&lt;/p&gt;
&lt;p&gt;It seems somewhat foolish to try and project Western ideals onto a Russian culture. It doesn&amp;rsquo;t seem to work.&lt;/p&gt;
&lt;p&gt;Well, it works to some extent. But not in the way one would like &amp;ndash; there&amp;rsquo;s a fundamental lack of engineering culture, however we try to tell ourselves the opposite, and whatever we do is essentially a bit like trying to promote Communism &amp;ndash; a goal that seems hopeless given the public&amp;rsquo;s general disinteterest. And while we won&amp;rsquo;t give up (after all, plenty of people &lt;em&gt;are&lt;/em&gt; interested in programming to the extent they will visit our meetings), it does affect the strategy that can be chosen given the current social as well as economic climate.&lt;/p&gt;
&lt;p&gt;I see two things happening. First, the &lt;a href="http://spbalt.net"&gt;group&lt;/a&gt; will contrinue to grow at a very small rate (I doubt we&amp;rsquo;ll ever have &amp;gt;50 people unless we cheat), so what we need to do is focus on the &lt;em&gt;quality&lt;/em&gt; of the meetings rather than, say, on getting ourselves funding or even a better room.&lt;/p&gt;
&lt;p&gt;The second thing I see coming is a shift of focus towards creating an environment where engineering culture can be nurtured in such a way that it doesn&amp;rsquo;t get significantly moderated by the fact that we live in Russia and not elsewhere. This is tough &amp;ndash; there are some companies (e.g., &lt;a href="http://www.dataart.ru"&gt;this one&lt;/a&gt;) that manage to create great developer atmosphere and whatnot, but I&amp;rsquo;m after something more &lt;em&gt;inclusive&lt;/em&gt; where the place you work doesn&amp;rsquo;t matter. It should be cool enough to just be a .Net developer.&lt;/p&gt;
&lt;p&gt;Unfortunately, engineering culture can only be created in the context of a &lt;em&gt;company, not a community&lt;/em&gt;. In other words, what makes great engineers great appears to be, at least given the situation, to be large amounts of &lt;em&gt;money&lt;/em&gt;. We need to be able to afford changes financially before we try proposing them. Of course, this implies levying the burden from the decrepit and corrupt education systems that teaches people using last-century textbooks and whatnot. And that makes the whole proposition even harder.&lt;/p&gt;
&lt;p&gt;To sum up, we won&amp;rsquo;t change the world: we&amp;rsquo;ll make it fun for ourselves and a few people but without business incentives, promotion of engineering culture is doomed to fail with all but the most fanatical of people. And I guess this is okay. After all, our jobs might one day end up at India or China, in which case we&amp;rsquo;ll pat ourselves on the back and say thanks that we didn&amp;rsquo;t invest into IT more than we should have.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/cY-k8bbrmwo" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/cY-k8bbrmwo/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/Promotion-of-engineering-culture.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=ce2b9cc4-d353-42a7-a5f9-9853b05a0c28</guid>
      <pubDate>Mon, 29 Jun 2009 14:59:00 +0300</pubDate>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=ce2b9cc4-d353-42a7-a5f9-9853b05a0c28</pingback:target>
      <slash:comments>0</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=ce2b9cc4-d353-42a7-a5f9-9853b05a0c28</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/Promotion-of-engineering-culture.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=ce2b9cc4-d353-42a7-a5f9-9853b05a0c28</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=ce2b9cc4-d353-42a7-a5f9-9853b05a0c28</feedburner:origLink></item>
    <item>
      <title>More user group activity at St. Petersburg!</title>
      <description>&lt;p&gt;Apart from caring for the wonderful &lt;a href="http://spbalt.net"&gt;St. Petersburg Alt.Net&lt;/a&gt; group (my baby), I&amp;rsquo;ve also been asked (volunteered, however you put it) to help run the &lt;a href="http://sp.ineta.ru"&gt;St. Petersburg .Net User Group&lt;/a&gt;, which is an &lt;a href="http://ineta.org"&gt;Ineta&lt;/a&gt;-affiliated enterprise. Unlike the Alt.Net group (which has just had its 8&lt;sup&gt;th&lt;/sup&gt; meeting, with ~20 people attending), the .Net UG has been somewhat quiet, with few meetings and hardly anything extraordinary. That&amp;rsquo;s about to change.&lt;/p&gt;
&lt;p&gt;The idea behind Ineta&amp;rsquo;s group is rougly this: showing that Microsoft stuff is cool. I mean, that&amp;rsquo;s why we&amp;rsquo;re in this business of .Net &amp;ndash; because it&amp;rsquo;s cool. But simply saying &amp;lsquo;it&amp;rsquo;s cool&amp;rsquo; isn&amp;rsquo;t, in itself, cool enough &amp;ndash; we need to show how to get the coolness out of tools like Visual Studio and technologies such as WPF. Great examples, lively demos and lots of fun are ways to guarantee that people who have never programmed .Net would want to move their carreers in this direction.&lt;/p&gt;
&lt;p&gt;But what about the competition? Well, honestly, there isn&amp;rsquo;t much &amp;ndash; except for Java, who was the topic of focus at the &lt;a href="http://developers.sun.com/events/techdays/"&gt;Sun TechDays&lt;/a&gt; here in St. Petersburg. Hundreds of people from St. Petersburg, Moscow and other places around Russia attended. It was a real high-profile show, with foreign speakers extolling the virtues of JavaFX and whatnot. I was there &amp;ndash; it was a little crowded but fun overall.&lt;/p&gt;
&lt;p&gt;The third developer camp is of course the C++ camp, largely driven by embedded, rather than desktop, development. As far as I know, the C++ people do not have a &amp;lsquo;user group&amp;rsquo; of any kind, partly due to the fact that the C++ establishment is by its very nature more conservative and less agile than either C# or Java.&lt;/p&gt;
&lt;p&gt;Whatever the case may be, I personally am excited about the new opportunity. We&amp;rsquo;ll see if I can make something out of it&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/yf8nwFQ2UEM" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/yf8nwFQ2UEM/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/More-user-group-activity-at-St-Petersburg!.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=3a4bc660-a4db-4720-89d7-262e22178778</guid>
      <pubDate>Fri, 26 Jun 2009 15:38:00 +0300</pubDate>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=3a4bc660-a4db-4720-89d7-262e22178778</pingback:target>
      <slash:comments>7</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=3a4bc660-a4db-4720-89d7-262e22178778</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/More-user-group-activity-at-St-Petersburg!.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=3a4bc660-a4db-4720-89d7-262e22178778</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=3a4bc660-a4db-4720-89d7-262e22178778</feedburner:origLink></item>
    <item>
      <title>Too Many Parallelization Frameworks?</title>
      <description>&lt;p&gt;
I think there&amp;#39;s far too much stuff going on with respect to parallelization on the .Net scene. Just off the top of my head, I can think of Task Parallel Library, Axum, all those weird Spec#-esque languages (okay, they aren&amp;#39;t exactly being released, but still), the Concurrency Coordination Runtime (which, let&amp;#39;s face it, is similar to what Spec#/Polyphonic C#/C&amp;omega; are doing, which is join calculus), and then there&amp;#39;s things like join macros in Nemerle (I beleive they are called &amp;#39;chords&amp;#39; by many people now). And let&amp;#39;s not forget F# async workflows.
But wait, we also have Intel releasing a huge unmanaged (plain C++) stack on us as well. And Microsoft! So the number of three-letter acronyms (PPL, TBB, MKL and IPP) is sharply on the rise, but are we actually better coders because of it? Do we really have time to learn it all?
&lt;/p&gt;
&lt;p&gt;
I don&amp;#39;t. I wish I did. Lots of stuff is a lot of fun, but some of the stuff is just a rehash of the same idea over and over. For example, we&amp;#39;ve &lt;em&gt;always&lt;/em&gt; had task-level parallelism, we were just either too lazy to do it properly, or we were feeling helpless and waiting for some miracle framework that will give us a &amp;#39;fair&amp;#39; ThreadPool (called TaskManager, as it happens) that will distribute work properly because, apparently, ThreadPool doesn&amp;#39;t get it quite right. And async workflows? Come on, we have the &lt;code&gt;AsyncEnumerator&lt;/code&gt; that does it in C#. Exploiting the F# workflow semantics is very cute but, given the abrupt change in the coding style that&amp;#39;s required, I&amp;#39;m not sure it&amp;#39;s worth the bother. I can download web pages asynchronously in C# too, thank you very much.
&lt;/p&gt;
&lt;p&gt;
Then there&amp;#39;s data-level parallelism, that ubiquitous &lt;code&gt;Parallel.For&lt;/code&gt; that we now have (or are about to have) as a way of blind separation of data into chunks. But, seriously, as soon as this tech started getting previewed, lots of people wrote the same implementation for .Net 2.0. So we could have had that too, ages ago.
&lt;/p&gt;
&lt;p&gt;
And let&amp;#39;s not talk of instruction-level parallelism because, really, .Net &lt;em&gt;could&lt;/em&gt; easily support it (hey, Mono does), but for some reason all that SIMD goodness is lost on the .Net code. Which is a pity because sometimes it is a real benefit, and I for one am tired of using those weird &lt;code&gt;__m128&lt;/code&gt; types and lots of pointer arithmetic and such.
&lt;/p&gt;
&lt;p&gt;
And don&amp;#39;t get me started on Axum and the join semantics.
&lt;/p&gt;
&lt;p&gt;
Just before I go off and stop ranting, I have to take a shot at PPL (Parallel Pattern Library), too. Seriously, we &lt;em&gt;already&lt;/em&gt; have OpenMP support (which is fantastic, and 3.0 ought to be even more brill), and TBB has been out - what - a year, maybe? Maybe less, but introducing PPL into VS2010 seems like a last-ditch attempt to get people to &lt;em&gt;not&lt;/em&gt; spend money on the Intel compiler and parallelization stack.
&lt;/p&gt;
&lt;p&gt;
To sum things up (because this is starting to sound like a rand instead of a normal blog post), I personally am sticking with OpenMP, SSE/2 and the Intel stack for all the parallelization stack. P/invoke only looks scary, but you only need to learn it once. As for .Net 4.0 and all that Task/Future business - well, we shall see what comes of it. But, beleive me, the people who &lt;em&gt;want&lt;/em&gt; to get good parallelization and multicore scalability &lt;em&gt;are getting it already&lt;/em&gt;. And to those who are still doing their matrix math in C# on a single thread - well, I leave you to your own devices.
&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/rIDj-nk0iDg" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/rIDj-nk0iDg/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/Too-Many-Parallelization-Frameworks.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=96153227-7401-4615-8824-2b409c208081</guid>
      <pubDate>Sun, 21 Jun 2009 00:18:00 +0300</pubDate>
      <category>c#</category>
      <category>c++</category>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=96153227-7401-4615-8824-2b409c208081</pingback:target>
      <slash:comments>6</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=96153227-7401-4615-8824-2b409c208081</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/Too-Many-Parallelization-Frameworks.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=96153227-7401-4615-8824-2b409c208081</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=96153227-7401-4615-8824-2b409c208081</feedburner:origLink></item>
    <item>
      <title>A Crazy C# Question</title>
      <description>&lt;p&gt;Today I really fell over while trying to answer a question about a (fairly stupid) C# expression. It went something like the following:&lt;/p&gt;
&lt;p&gt;Consider the following code:&lt;/p&gt;
&lt;blockquote&gt;&lt;code&gt;&lt;font size="2" face="Consolas, Andale Mono, Courier New" color="black"&gt;&lt;font color="#00008B"&gt;int&lt;/font&gt; i = 0;&lt;br/&gt;
&lt;font color="#00008B"&gt;while&lt;/font&gt; (i &amp;lt; 10)&lt;br/&gt;
{&lt;br/&gt;
&amp;nbsp;&amp;nbsp;Console.WriteLine(i++);&lt;br/&gt;
}&lt;br/&gt;
&lt;font color="#00008B"&gt;while&lt;/font&gt; (i &amp;gt;= 10);&lt;br/&gt;
&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;&lt;p&gt;This code:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Will not compile&lt;/li&gt;
&lt;li&gt;Will print numbers from 0..9&lt;/li&gt;
&lt;li&gt;Will print numbers from 0..9 and then 9 forever&lt;/li&gt;
&lt;li&gt;Will print numbers from 0 to &amp;#8734;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Something like this. At first I thought this wouldn&amp;rsquo;t compile, but in fact my SnippetCompiler ate it just fine. I thought I was going insane. Then I assumed that this construct is, in fact, allowed (maybe a bug in the C# language spec?) and it acts as a double-ended do, cycling the precondition &lt;code&gt;while&lt;/code&gt; before cycling the postcondition &lt;code&gt;while&lt;/code&gt;, thus yielding the answer 4.&lt;p&gt;
&lt;p&gt;And then it finally hit me: a while loop doesn&amp;rsquo;t need a comma after it. What this meant is that you could write the code as follows:&lt;/p&gt;
&lt;/p&gt;
&lt;blockquote&gt;&lt;code&gt;&lt;font size="2" face="Consolas, Andale Mono, Courier New" color="black"&gt;&lt;font color="#00008B"&gt;int&lt;/font&gt; i = 0;&lt;br/&gt;
&lt;font color="#00008B"&gt;while&lt;/font&gt; (i &amp;lt; 10)&lt;br/&gt;
{&lt;br/&gt;
&amp;nbsp;&amp;nbsp;Console.WriteLine(i++);&lt;br/&gt;
}&lt;br/&gt;
&lt;font color="#006400"&gt;// &lt;strong&gt;empty&lt;/strong&gt; while loop!&lt;br/&gt;&lt;/font&gt;
&lt;font color="#00008B"&gt;while&lt;/font&gt; (i &amp;gt;= 10);&lt;br/&gt;
&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt;&lt;p&gt;It was a trick question, of course, but it goes to show that vigilance against blatant trickery is often more useful than scientific analysis. Another lesson learned.&lt;/p&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/3UB5_rUtfEI" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/3UB5_rUtfEI/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/A-Crazy-C-Question.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=e2789268-3bbd-4009-adfa-0662431545d7</guid>
      <pubDate>Tue, 16 Jun 2009 00:50:00 +0300</pubDate>
      <category>c#</category>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=e2789268-3bbd-4009-adfa-0662431545d7</pingback:target>
      <slash:comments>6</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=e2789268-3bbd-4009-adfa-0662431545d7</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/A-Crazy-C-Question.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=e2789268-3bbd-4009-adfa-0662431545d7</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=e2789268-3bbd-4009-adfa-0662431545d7</feedburner:origLink></item>
    <item>
      <title>Are non-automatic properties evil?</title>
      <description>Ever since the introduction of automatic properties in C#, I&amp;rsquo;ve been thinking about whether they should, in fact, be the only type of property that&amp;rsquo;s allowed. The reasoning behind the idea is very simple: if something magical is happening inside an auto-property (i.e., something beyond the typical store/load), then this something is a piece of domain logic or a non-functional requirement that has somehow crept into the entity/persistence layer. The typical result of this is code like the following:
&lt;pre&gt;&lt;code&gt;
public int Age {
  get {
    return age;
  }
  set {
    // copious amounts of voodoo
    if (age != value)
    {
      age = value;
      NotifyPropertyChanged("Age");
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
This code is creepy for several reasons, the main being that end-users of this code won&amp;rsquo;t have a clue as to why the Age variable is behaving the way it does. Unless you document that it prevents self-assignment and notifies on change, that is. And even if you do that, would people then assume that &lt;em&gt;every&lt;/em&gt; property in the class behaves this way? You never know, really! You&amp;rsquo;ve just introduced lots of ambiguity that is unresolvable without either a good look at the code or, failing that, Reflector.
The above example is only the tip of the iceberg, because really, many people know about self-assignment checks and the &lt;code&gt;INotifyPropertyChanged&lt;/code&gt; interface. But what if we do even more hackery inside the property?
&lt;pre&gt;&lt;code&gt;
public int Age {
  get {
    return person.Age;
  }
  set {
    // even more obscure voodoo
    if (value &amp;gt;= 16)
      person = new Adult(value);
    else
      person = new Minor(value);
  }
}
&lt;/code&gt;&lt;/pre&gt;
More trouble! Now you have some &lt;em&gt;real&lt;/em&gt; voodoo happening inside the property. What if someone else decides to use the &lt;code&gt;person&lt;/code&gt; field without knowledge of what your &lt;code&gt;Age&lt;/code&gt; variable does? And what if &lt;em&gt;every&lt;/em&gt; property in this class needs to be done this way, but developers forget about it? They are doomed!
My take on making properties is to simply write the following:
&lt;pre&gt;&lt;code&gt;
public int Age { get; private set; }
&lt;/code&gt;&lt;/pre&gt;
That&amp;rsquo;s right &amp;ndash; I make &lt;code&gt;Age&lt;/code&gt; pseudo-immutable, i.e., only assignable from within the class. That way, we don&amp;rsquo;t get into a situation where people haphazardly assign the value from several different threads. Of course, we also lose all the interesting stuff like self-assignment checks or change notification, but we can get them back &amp;ndash; all we have to do is sprinkle some AOP on top of the class, and we&amp;rsquo;re good to go. For example, we can declaratively turn every property into a WPF-style dependency property, all without having to use the &lt;code&gt;propdp&lt;/code&gt; snippet and having extra &lt;code&gt;static XxxProperty&lt;/code&gt; fields in our code.
In fact, there are several &lt;em&gt;more&lt;/em&gt; things you can do with properties. First, you can use fields instead! After all, PostSharp (if that&amp;rsquo;s what you&amp;rsquo;re using) doesn&amp;rsquo;t care what to rewrite, and making a field is easier&amp;mdash;but you do lose declarative immutability. What I mean is, you can just write the following:
&lt;pre&gt;&lt;code&gt;
public int Age;
&lt;/code&gt;&lt;/pre&gt;
You might have FxCop complain about a public field, but feel free to ignore it. Public fields are perfectly okay in the general case too, of course, but that&amp;rsquo;s another story.&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/JvIKFQ4kVi0" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/JvIKFQ4kVi0/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/Are-non-automatic-properties-evil.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=e63f7b01-63a0-43bf-91bc-ab01b07c0fd1</guid>
      <pubDate>Sat, 06 Jun 2009 15:33:00 +0300</pubDate>
      <category>c#</category>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=e63f7b01-63a0-43bf-91bc-ab01b07c0fd1</pingback:target>
      <slash:comments>20</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=e63f7b01-63a0-43bf-91bc-ab01b07c0fd1</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/Are-non-automatic-properties-evil.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=e63f7b01-63a0-43bf-91bc-ab01b07c0fd1</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=e63f7b01-63a0-43bf-91bc-ab01b07c0fd1</feedburner:origLink></item>
    <item>
      <title>Visual Studio 2010 Beta 1 Screenshots</title>
      <description>&lt;p&gt;I&amp;rsquo;ve been using Visual Studio since version 5. In those days, I ran it on a computer with 16Mb (!!!) RAM and a 166MHz processor and was, for the most part, happy with the performance. At the time, MFC was the way to make attractive GUI apps, but I also spent a lot of time obsessing over C++, replacing the compiler and the STL with versions that allowed me to weave that Generative Programming magic that was becoming popular.&lt;/p&gt;

&lt;p&gt;Now, a decade down the line, we have a new release of Visual Studio. I have barely touched 2010, but with Beta 1 released I felt like downloading it off the subscription and having fun with it.&lt;/p&gt;

&lt;h3&gt;Installation&lt;/h3&gt;
&lt;p&gt;It&amp;rsquo;s weird, but there were two checkboxes for installation &amp;ndash; to install support for .NET development and C++ development. That&amp;rsquo;s it. It&amp;rsquo;s totally weird. In other respects, the installation is the same as Visual Studio 2008, installing about 15 different components (such as .NET Framework 4, which casuese a restart) one after another.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;m not a fan of these large 4Gb undiscriminated installs. Lots of stuff, such as Sync Framework and SQL Server should be installed only if you work with those technologies. I&amp;rsquo;m using a WinXP virtual machine, so these extra features carry a price in terms of both the waiting time and the performance costs.&lt;/p&gt;

&lt;p align="center"&gt;
  &lt;img src="http://nesteruk.org/blog/pics/vs2010/1.png"/&gt;
&lt;/p&gt;

&lt;h3&gt;First few screens&lt;/h3&gt;
&lt;p&gt;The opening screen is a re-hash of the same ideas that have been around since VS2005. I had to collapse the Solution pane because the whole thing wouldn&amp;rsquo;t fit on my 800&amp;times;600 window.&lt;/p&gt;

&lt;p align="center"&gt;
  &lt;img src="http://nesteruk.org/blog/pics/vs2010/2.png"/&gt;
&lt;/p&gt;

&lt;p&gt;One thing that VS and other programs haven&amp;rsquo;t learned to handle well yet is the absence of an internet connection. It&amp;rsquo;s not a given! And I don&amp;rsquo;t really want to be reminded that I&amp;rsquo;m missing on the RSS feed that goes into Visual Studio. Thanks but no thanks.&lt;/p&gt;

&lt;p&gt;The project system is pretty much the same, with the idea that there is only one language (C#) and all languages fall into that elusive &amp;ldquo;Other Language&amp;rdquo; category. Care to guess what languages are kept there? C++, Visual Basic, and F#.&lt;/p&gt;

&lt;p align="center"&gt;
  &lt;img src="http://nesteruk.org/blog/pics/vs2010/3.png"/&gt;
&lt;/p&gt;

&lt;h3&gt;Making a WPF app&lt;/h3&gt;
&lt;p&gt;Just for fun, I decided to make a WPF app. One thing I noticed immediately is that the WPF property pane was properly done, with special editors and all.&lt;/p&gt;

&lt;p align="center"&gt;
  &lt;img src="http://nesteruk.org/blog/pics/vs2010/4.png"/&gt;
&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s hard to notice that the editor uses WPF unless you try something like selecting text, shown below. &lt;/p&gt;

&lt;p align="center"&gt;
  &lt;img src="http://nesteruk.org/blog/pics/vs2010/5.png"/&gt;
&lt;/p&gt;

&lt;p&gt;I was kind of expecting closing braces to &amp;lsquo;pop up&amp;rsquo; like they do in XCode (the Mac IDE), but alas. The Add Reference dialog is, so far, still that same boring (and horribly inefficient) window. Notice that Blueprints, the tech that is meant to succeed Guidance Automation, is already in the GAC for some reason. I&amp;rsquo;m guessing it will be included in 2010.&lt;/p&gt;

&lt;p align="center"&gt;
  &lt;img src="http://nesteruk.org/blog/pics/vs2010/6.png"/&gt;
&lt;/p&gt;
 
&lt;h3&gt;Extra windows&lt;/h3&gt;
&lt;p&gt;There&amp;rsquo;s now a Call Hierarchy window that lets you determine who calls a particular method, and which other methods this one calls:&lt;/p&gt;

&lt;p align="center"&gt;
  &lt;img src="http://nesteruk.org/blog/pics/vs2010/7.png"/&gt;
&lt;/p&gt;
 
&lt;p&gt;The Code Definition pane is even more useful &amp;ndash; it can show you the actual body of the method you&amp;rsquo;re interested in. In our case, it can open the &lt;code&gt;.g.cs&lt;/code&gt; file and show us the body of the (typically hidden) &lt;code&gt;InitializeComponent()&lt;/code&gt; method:&lt;/p&gt;

&lt;p align="center"&gt;
  &lt;img src="http://nesteruk.org/blog/pics/vs2010/8.png"/&gt;
&lt;/p&gt;
 
 
&lt;p&gt;One cute thing is &amp;lsquo;watch floats&amp;rsquo; or whatever they are called. Basically, you can hover the mouse over a variable while debugging, and then &lt;em&gt;detach&lt;/em&gt; the property strip, letting it stick on the screen as a kind of Post-It note:&lt;/p&gt;

&lt;p align="center"&gt;
  &lt;img src="http://nesteruk.org/blog/pics/vs2010/9.png"/&gt;
&lt;/p&gt;
 
&lt;p&gt;That&amp;rsquo;s as much as I have explored so far&amp;hellip; might post more screenshots later.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/FUm3ADuOPTw" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/FUm3ADuOPTw/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/Visual-Studio-2010-Beta-1-Screenshots.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=7b1fdb61-09b6-4c08-9730-97634c38ad31</guid>
      <pubDate>Wed, 20 May 2009 12:25:00 +0300</pubDate>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=7b1fdb61-09b6-4c08-9730-97634c38ad31</pingback:target>
      <slash:comments>2</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=7b1fdb61-09b6-4c08-9730-97634c38ad31</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/Visual-Studio-2010-Beta-1-Screenshots.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=7b1fdb61-09b6-4c08-9730-97634c38ad31</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=7b1fdb61-09b6-4c08-9730-97634c38ad31</feedburner:origLink></item>
    <item>
      <title>What is Data-Driven Design?</title>
      <description>&lt;p&gt;When asked about the meaning of life, one colleague of mine commented once that &amp;ldquo;I don&amp;rsquo;t know, but I know that nobody else knows either.&amp;rdquo; The same approach, I suppose, could be taken with respect to data-driven design: it isn&amp;rsquo;t clearly defined (good luck &lt;a href="http://en.wikipedia.org/wiki/Data-driven_design"&gt;on Wikipedia&lt;/a&gt;), and actually means different things to different people. Consequently, the best thing I can do is describe what it means to me, thereby making it a kind of &amp;lsquo;Dmitri&amp;rsquo;s data-driven design&amp;rsquo;. Still, given the relative scarcity of information on this paradigm (that Wikipedia article is a good indication), I think every little helps.&lt;/p&gt;

&lt;p&gt;The idea of data-driven design, for me, is simple: data-driven design is a paradigm in which some nebulous data (which is, predictably, stored somewhere) drives all, or a large portion, of an application. In other words, the application infrastructure is malleable, and aligns itself to the needs of the data. Here, we can specify two different patterns of application:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Static&lt;/strong&gt; data-driven design is akin to code generation: you have some data (an abstract model), and this data is transformed before compilation to produce an application, or a significant part of it. As an example, abstract data definitions in XML can be transformed via XSLT/XQuery/T4/whatever in order to produce necessary stored procedures, entity objects/mappings, and the user interface. In this respect, of course, data-driven design appears to be synonymous with either code generation or &lt;a href="http://en.wikipedia.org/wiki/Metaprogramming"&gt;metaprogramming&lt;/a&gt;, depending on how you look at it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dynamic&lt;/strong&gt; data-driven design is when data continuously defines how your application looks. For example, if a UI is generated &lt;em&gt;dynamically&lt;/em&gt; from a database at run-time, you&amp;rsquo;ve got dynamic data-driven design. Admittedly, the dynamic approach is more powerful since it allows you to project changes to data immediately, instead of when the application is recompiled. However, this approach is also a lot more complicated and requires more metadata in the data you&amp;rsquo;ve got.&lt;/p&gt;

&lt;p&gt;I am an advocate of &lt;em&gt;static&lt;/em&gt; DaDD, because generation implies a higher degree of malleability. For example, in a dynamic scenario you corner yourself into a particular persistence scenario, and it is very difficult to suddenly change the persistence method mid-project. On the other hand, if your application is a &lt;em&gt;compile-time derivative&lt;/em&gt; of some abstract data specification, you get massive benefits in the form of an ability to retarget the application to whatever language or platform you see fit. In a similar dynamic setting, you would need to re-engineer the persistence layer, unless of course you started out with persistence ignorance in mind.&lt;/p&gt;

&lt;p&gt;Dynamic DaDD is infinitly more complex because you get the interplay of various actors in the system that can also use &lt;em&gt;their&lt;/em&gt; data to drive &lt;em&gt;your&lt;/em&gt; software. For example, an engineer writes a formula that gets fed as input data to your system. Great, right? Except it doesn&amp;rsquo;t work that well, and a much better approach is to &lt;a href="http://code.google.com/p/mmlsharp"&gt;pre-translate&lt;/a&gt; the formula to a programming notation &lt;em&gt;beforehand&lt;/em&gt;, so that any bugs or inconsistencies can be discovered before the whole thing is shipped to the customers. After all, how do you &lt;em&gt;prove&lt;/em&gt; that mathematical data will drive your system correctly in 100% of cases? That&amp;rsquo;s right &amp;ndash; you cannot.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s an example of dynamic data-driven design: games scripting. The idea behind scripting is that it&amp;rsquo;s not the programmers&amp;rsquo; business to create, say, in-game interactions, but rather the story designers. So, some of the tasks are offloaded to the storywriters, and the scripts they write are plugged in at either compile-time or run-time into the system. When I was young, I remember fiddling with the scripting of &lt;a href="http://en.wikipedia.org/wiki/Icewind_dale"&gt;Icewind Dale&lt;/a&gt;, which involved using a strange language to determine the AI that drove my characters&amp;rsquo; actions. For simple decisions it was fine, but for a very complicated logic system, its interpret nature ground the game to a halt. Nowadays, this sort of data-driven thing still works, but if you look at language workbenches such as &lt;a href="http://www.aspfree.com/c/a/BrainDump/Build-a-Domain-Specific-Language-with-DSL-Tools/"&gt;Microsoft DSL Tools&lt;/a&gt;, you&amp;rsquo;ll see that they are mainly geared towards &lt;em&gt;compiled&lt;/em&gt; code, rather than the creation of scripts and an in-code interpreter.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s one example where dynamic data-driven approach makes perfect sense. Suppose you&amp;rsquo;re writing some sort of Excel integration package where you want end users (who are familiar with Excel) to keep editing their sheets as always, but interoperate with some heavier tech (e.g., BizTalk) in order to aggregate data. In this case, precompiling the formulae in the spreadsheets would be somewhat pointless, because the interaction of formulae on a spreadsheet presents a very complicated, and &lt;em&gt;inherently dynamic&lt;/em&gt; scenario of execution.&lt;/p&gt;

&lt;p&gt;In my opinion, a dynamic, purely data-driven application only makes sense in cases where the variability of options and the frequency of changes is such that the application has to be constantly adaptable to the end-users&amp;rsquo; wishes. But if there&amp;rsquo;s a need in maximum performance or maximum support for features inherent in the chosen framework, then the precompilation approach is more advisable.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/POAzPdsQQ2U" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/POAzPdsQQ2U/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/What-is-Data-Driven-Design.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=ff859113-8de8-4370-a86a-b2205bb93822</guid>
      <pubDate>Sun, 17 May 2009 18:55:00 +0300</pubDate>
      <category>dsl</category>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=ff859113-8de8-4370-a86a-b2205bb93822</pingback:target>
      <slash:comments>14</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=ff859113-8de8-4370-a86a-b2205bb93822</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/What-is-Data-Driven-Design.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=ff859113-8de8-4370-a86a-b2205bb93822</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=ff859113-8de8-4370-a86a-b2205bb93822</feedburner:origLink></item>
    <item>
      <title>Employer filtering</title>
      <description>&lt;p&gt;
As someone looking for a job, I often view the job description in order to try and analyze whether I should even bother applying to such-and-such a company. Recently, I realized that the process of determining whether a company is good or not can be completely automated. In other words, you can write a computer program that parses the job description and produces a score or some kind of index regarding the employer. Here are a few ideas:
&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;# of listed technologies. Basically, there is a &amp;#39;golden mean&amp;#39; of a number of technologies that a company should list for an opening. If the number is too small, the company is probably a bit clueless (or doesn&amp;#39;t care) regarding how software is made. (For example, they mention C#, full stop. It&amp;#39;s just plain silly.) On the other hand, there are job descriptions with 20 different skills required, sort of &amp;quot;C#/F#/C++ COM/IDL WinForms/WPF/WF NUnit TFS/Subversion&amp;quot; et cetera. It&amp;#39;s silly too because finding a person with all those skills is near-impossible, so you&amp;#39;ll have to compromise anyway. It&amp;#39;s not a sign of wisdom.&lt;br /&gt;
	&lt;br /&gt;
	&lt;/li&gt;
	&lt;li&gt;Old technology. As soon as I see COM in a job description I just ignore it. Don&amp;#39;t get me wrong - I&amp;#39;ve spent a lot of time working with COM/DCOM while at Uni, but I don&amp;#39;t remember much, and these are not the skills I want to be picking up again. Whatever company is looking for old tech (e.g., Cobol), they are probably looking for 40-year-old developers who are either too lazy or too inept to actually learn new stuff.&lt;br /&gt;
	&lt;br /&gt;
	&lt;/li&gt;
	&lt;li&gt;Microsoft bias. I often pick this one up when a job posting is 100% Microsoft tech. Yeah, I&amp;#39;m a .NET programmer, but when I see VsTest on the job description, I just know that the people I will be working with are not very smart. Same goes for requirements of Linq2Sql or EF - I mean, you like the framework, great, you use it. Unfortunately, this also affects some of the tools that I really like (e.g., TFS) because, although TFS is a great idea, let&amp;#39;s face it - the companies who &lt;em&gt;do&lt;/em&gt; use it are large soulless corporate monstrosities.&lt;br /&gt;
	&lt;br /&gt;
	&lt;/li&gt;
	&lt;li&gt;Vague wording with respect to things that people probably don&amp;#39;t understand themselves. Like when you write &amp;quot;should know how to manage requirements&amp;quot;. WTF?!? So some HR chick got an order from high-up to post an IT position with some vague guidelines, she follows them verbatim. Heh, I guess I should be thankful: those vague features are easy to spot. Not sure about computer processing though. &amp;quot;Work in a nice company&amp;quot;. Yeah, I like that. Very much. FAIL.&lt;/li&gt;
&lt;/ul&gt;
Overall, I think it might be possible to write a parser that can read in the job posting and determine whether it&amp;#39;s even worth bothering to apply. Of course, some of the stuff (e.g., the prospective co-workers&amp;#39; ineptness) might not come out immediately, but at least you can diagnose the really bad cases. Oh, and whenever there&amp;#39;s a line saying &amp;quot;overwork is nothing common&amp;quot; a big blue-and-yellow swedish flag can pop up. Yeah. That would be cool. Hehe.&lt;br /&gt;
&lt;p&gt;
&amp;nbsp; 
&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/Mw-l3UkiNLc" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/Mw-l3UkiNLc/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/Employer-filtering.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=857bb737-b481-41b3-a2b0-afa593a5b43b</guid>
      <pubDate>Wed, 13 May 2009 21:32:00 +0300</pubDate>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=857bb737-b481-41b3-a2b0-afa593a5b43b</pingback:target>
      <slash:comments>1</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=857bb737-b481-41b3-a2b0-afa593a5b43b</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/Employer-filtering.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=857bb737-b481-41b3-a2b0-afa593a5b43b</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=857bb737-b481-41b3-a2b0-afa593a5b43b</feedburner:origLink></item>
    <item>
      <title>Start-up Woes</title>
      <description>&lt;p&gt;
Over the past few months, I have been toying with the idea of opening a start-up company to explore some of the ideas that I&amp;#39;ve come up with over the years (or, ones that other people came up with). To date, nothing has come of it, and I kind of realize why. Basically, there are several essential hurdles that I haven&amp;#39;t managed (yet) to overcome.
&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;I don&amp;#39;t have one central idea. Instead, I have about 4 proposals that can be said to be mature, but none of the ideas really &amp;#39;shines&amp;#39;. Sure, they are all unique in their ways, but not to the extent where they make you go &amp;#39;wow, this might really work&amp;#39;.&lt;/li&gt;
	&lt;li&gt;I am somewhat inept when it comes to doing a financial write-up. Truth be told, I&amp;#39;d actually prefer it if someone did this for me.&lt;/li&gt;
	&lt;li&gt;I am somewhat unsure about being part of a team. I am unlikely to meet anyone who, e.g., speaks English to the same standard as I would like. People sure have computer skills, but that&amp;#39;s probably not as important.&lt;/li&gt;
	&lt;li&gt;I am anxious about starting a company in Russia. Of course, start-ups don&amp;#39;t really get registered in Russia (I bet you knew that already), but operating any kind of business here seems like a risk, especially if you have no solid foundations elsewhere. By &amp;#39;elsewhere&amp;#39;, I mean either the UK or the USA.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
One other thing that&amp;#39;s a little disappointing (but only a little) is that one of my ideas was, ahemm, &amp;#39;appropriated&amp;#39; by some nice people. Of course, my idea was subtly different than theirs, but it&amp;#39;s still a bit weird.
&lt;/p&gt;
&lt;p&gt;
So, just to sum up what&amp;#39;s going on at the moment, I am sitting on a couple of nice ideas that are probably not going to work, for whatever reasons. However, all these thought processes might get me to come up with something truly sellable. That being the case, I will try to find an agency that can take the idea without a massive write-up because, truth be told, I am not particularly qualified in order to do one. 
&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/2IYh3AQ3SQ4" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/2IYh3AQ3SQ4/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/Start-up-Woes.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=a5d43cbf-7930-4396-8e35-0c7340df4470</guid>
      <pubDate>Mon, 11 May 2009 23:59:00 +0300</pubDate>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=a5d43cbf-7930-4396-8e35-0c7340df4470</pingback:target>
      <slash:comments>2</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=a5d43cbf-7930-4396-8e35-0c7340df4470</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/Start-up-Woes.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=a5d43cbf-7930-4396-8e35-0c7340df4470</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=a5d43cbf-7930-4396-8e35-0c7340df4470</feedburner:origLink></item>
    <item>
      <title>Defending code generation</title>
      <description>&lt;p&gt;As a practitioner of code generation in its various guises, I&amp;rsquo;m always intrigued by anyone who proclaims that code generation is somehow bad or evil (e.g., &lt;a href="http://www.codethinked.com/post/2009/05/05/Code-Generation-Should-be-the-Nuclear-Option.aspx"&gt;this post&lt;/a&gt;). Since this subject has been raised in people&amp;rsquo;s blogs, like, a zillion times, I cannot help but think that anything I write to defend the practice of code generation is like a drop in a lake of tears shed by developers who have had negative experiences with code generation.&lt;/p&gt;
&lt;/p&gt;
&lt;p&gt;So here&amp;rsquo;s a collection of some (fairly strong) statements that I would offer as my way of explaining whether or not code generation is of any use in business.&lt;/p&gt;
&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s be honest &amp;ndash; code generation is &lt;strong&gt;very powerful&lt;/strong&gt;, because as soon as you have figured out a method to save time by automating something, you are producing lots of code with ease. But, like they say in Spiderman, with great power comes great responsibility. What this means is that:&lt;/p&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You can forget about modifying generated code. It&amp;rsquo;s just not kosher. Partial classes, partial methods, text injection and other tricks are used for that. If you need to modify generated code, &lt;strong&gt;you&amp;rsquo;re doing it wrong&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You can forget about computing the Maintainability Index or using a sly tool like NDepend to infer data about the generated assembly. &lt;strong&gt;Generated code != hand-written code.&lt;/strong&gt; The former is not subject to the same quality control procedures, because &lt;strong&gt;the quality of generated code is a derivative of whatever template or alorithm was used to make it&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you are using code generation effectively (i.e., getting an output between 3&amp;times; and 10&amp;times; the size of input), then &lt;strong&gt;you will never have perfect test coverage&lt;/strong&gt;. Not even close. Generated code must be tested, but &lt;strong&gt;it is not subject to unit testing in the same degree as hand-written code&lt;/strong&gt;. The reason should be obvious &amp;ndash; if the same template results in the generation of 20 sprocs (one for each entity), it is unrealistic to aim for 100% coverage if they all contain variations on a single theme.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now, with all this power, there comes a substantial &lt;strong&gt;skills risk&lt;/strong&gt; that people write about. Essentially, it sounds something like this: &amp;ldquo;oh but what if other developers can&amp;rsquo;t make heads or tails of my code generation scaffolding?&amp;rdquo; Addmittedly, the skills risk is there, but let&amp;rsquo;s discuss it in detail:&lt;/p&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;One side effect of code generation is to &lt;strong&gt;simplify things&lt;/strong&gt; &amp;ndash; for example, the models I build in XML are fairly human-readable, and contain a fraction of the &amp;lsquo;footprint&amp;rsquo; that would be generated by hordes of SQL and CS files that I would otherwise have. Everything is compact and understandable. So if the source materials for your generation are incomprehensible, well, guess what, &lt;strong&gt;you&amp;rsquo;re doing it wrong&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If your developers are fundamentally incapable of learning a language or two in order to become more effective then yeah, &lt;strong&gt;code generation is not for you&lt;/strong&gt;. If that&amp;rsquo;s the case though, you might think of changing jobs because, personally, I think it&amp;rsquo;s more worthwhile working with people that can learn new things instead of stagnating their skills. It&amp;rsquo;s all about progress, isn&amp;rsquo;t it?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Likewise, if you&amp;rsquo;re thinking of later moving product support to another, cheaper location with less qualified developers, then &lt;strong&gt;code generation is not for you&lt;/strong&gt; because the people you hire will start &lt;strong&gt;editing generatated code by hand&lt;/strong&gt;, introducing magic numbers, et cetera. They won&amp;rsquo;t bother even finding out how the code generation thing worked, and they certainly won&amp;rsquo;t bother learning something as &amp;lsquo;complex&amp;rsquo; as XSLT in order to improve the templates. In the end, you&amp;rsquo;ll most likely get an unmaintainable mess.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On the reverse side of the coin, code generation &lt;strong&gt;mitigates technological and financial risk&lt;/strong&gt;. Having the model as a simple XML file means that on the output you can get &lt;strong&gt;anything&lt;/strong&gt; &amp;ndash; your code can be in C# or C++ or Java, your sprocs can target MySql, Sql Server or Oracle, your ORM can be anything from NHibernate/EF/Linq2Sql to a generated ADO.NET framework. And so on, and so forth. With code generation, &lt;strong&gt;you can always change your mind&lt;/strong&gt;.&lt;/p&gt;
&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Here&amp;rsquo;s a real-life situation. A company that wanted a WinForms app chose DevExpress controls for its UI layer. Later, we as devs found out that some controls could not be tested by the automated testing tool. As a result, certain types of controls had to be changed back to WinForms. It was a nightmare, took ages, and the end result had bugs where the substitution wasn&amp;rsquo;t done just right.
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;To conclude, there&amp;rsquo;s something to be said for potential &lt;strong&gt;abuse&lt;/strong&gt; of code generation, i.e., using code generation to generate everything (even one-off code blocks) or, what&amp;rsquo;s worse, using code generation to generate lots of code bloat, such as, e.g., creating a &lt;code&gt;ToString()&lt;/code&gt; overload for every single class produced. Naturally, this is ineffective, which only goes to highlight that &lt;strong&gt;code generation requires judicious use&lt;/strong&gt;.&lt;/p&gt;
&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/A5Vuv0SIW_o" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/A5Vuv0SIW_o/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/Defending-code-generation.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=8f2f872f-1a0b-42c6-bd98-809d7a5b13d2</guid>
      <pubDate>Fri, 08 May 2009 14:23:00 +0300</pubDate>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=8f2f872f-1a0b-42c6-bd98-809d7a5b13d2</pingback:target>
      <slash:comments>7</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=8f2f872f-1a0b-42c6-bd98-809d7a5b13d2</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/Defending-code-generation.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=8f2f872f-1a0b-42c6-bd98-809d7a5b13d2</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=8f2f872f-1a0b-42c6-bd98-809d7a5b13d2</feedburner:origLink></item>
    <item>
      <title>Ideas for an IT book</title>
      <description>&lt;p&gt;For a very long time, I have been tempted to write a book, save it for the fact that books don&amp;rsquo;t sell and nobody is going to read it anyway. However, I&amp;rsquo;m thinking that if I write, say, one page a day, I might actually get somewhere within the course of a year or two. It requires amazing discipline, of course, but maybe I can muster some &amp;ndash; after all, I have several journals (&lt;a href="http://www.moleskine.com"&gt;Moleskine&lt;/a&gt; and &lt;a href="http://www.epica.com"&gt;Epica&lt;/a&gt;) that I have been writing in for about 5 years, every day, without fail. So persistence is not something I&amp;rsquo;m lacking.
&lt;/p&gt;
&lt;p&gt;What I&amp;rsquo;m lacking is something else &amp;ndash; a good idea for a book. After all, there are already plenty of books on programming languages (e.g., C#, F#, C++) and technologies. What can I write that could be useful and people would read? Just off the top of my head, here are some ideas:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Write about a language for which no book exists, such as &lt;a href="http://nemerle.org"&gt;Nemerle&lt;/a&gt; or &lt;a href="http://iolanguage.com"&gt;Io&lt;/a&gt;. Alternatively, I could write something on mixing and matching languages in the .NET stack. The trouble is, this requires &lt;em&gt;a lot&lt;/em&gt; of experience with different languages.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Write about an unreleased or up-and-coming product such as &lt;a href="http://en.wikipedia.org/wiki/Windows_Azure"&gt;Azure&lt;/a&gt; or &lt;a href="http://www.microsoft.com/visualstudio/en-us/products/2010/default.mspx"&gt;Visual Studio 2010&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Write about &lt;a href="http://martinfowler.com/bliki/DomainSpecificLanguage.html"&gt;DSL&lt;/a&gt;s. There aren&amp;rsquo;t that many books on DSLs, and I&amp;rsquo;m sure that many people are wondering &lt;em&gt;why&lt;/em&gt; there&amp;rsquo;s been so much talk of DSLs lately, and many are interested &lt;em&gt;how and where&lt;/em&gt; to use them. The most intriguing option is to use &lt;a href="http://www.jetbrains.com/mps/"&gt;JetBrains MPS&lt;/a&gt;, which looks to be a complicated and powerful DSL technology (too bad it&amp;rsquo;s Java-driven).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Write a methodological book on something like &lt;a href="http://postsharp.org"&gt;AOP&lt;/a&gt; or metaprogramming that people kind of like but aren&amp;rsquo;t sure about.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Write about some tech that&amp;rsquo;s a bit far out than people are used to. For example, there is &lt;a href="http://www.amazon.co.uk/DocBook-Definitive-Guide-Norman-Walsh/dp/1565925807/ref=sr_1_1?ie=UTF8&amp;s=books&amp;qid=1241620291&amp;sr=8-1"&gt;a book on DocBook&lt;/a&gt; and, let&amp;rsquo;s face it, not many people (even experienced developers) know what DocBook is, and there&amp;rsquo;s probably an even smaller number of people using it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Write an algorithms book. This is a good idea because, apart from going over implementation of various algorithms (e.g., &lt;a href="http://en.wikipedia.org/wiki/Pearson's_r"&gt;correlation calculation&lt;/a&gt; or &lt;a href="http://en.wikipedia.org/wiki/A_star"&gt;A*&lt;/a&gt;) it&amp;rsquo;s also possible to cover various programming languages and contrast, e.g., imperative vs. functional approaches. Unfortunately it also requires explaining about the basics of numeric computation, e.g. what &lt;code&gt;double.Epsilon&lt;/code&gt; means.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Write a statistics book. After all, collective intelligence of the type used on social networking websites is the kind of material that&amp;rsquo;s subject to statistics, so it could be a good topic.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Unmanaged parallelization. This is a subject of interest for me primarily because I want to write algorithms that scale, and the whole &lt;code&gt;TaskManager&lt;/code&gt; related .NET 4.0 business consistently fails to impress me.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At the moment, I&amp;rsquo;m not prepared to start writing anything major. I prefer to sit on the ideas and write a few &lt;a href="http://www.codeproject.com/script/Articles/MemberArticles.aspx?amid=49722"&gt;articles&lt;/a&gt; to explore the field and try to determine what people really want to read about. And who knows&amp;mdash;I might find something that&amp;rsquo;s worth a long-term effort.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/lkM7iDfzJiA" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/lkM7iDfzJiA/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/Ideas-for-a-book.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=70739129-f165-47e9-b776-9c8472ebf181</guid>
      <pubDate>Wed, 06 May 2009 18:51:00 +0300</pubDate>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=70739129-f165-47e9-b776-9c8472ebf181</pingback:target>
      <slash:comments>3</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=70739129-f165-47e9-b776-9c8472ebf181</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/Ideas-for-a-book.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=70739129-f165-47e9-b776-9c8472ebf181</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=70739129-f165-47e9-b776-9c8472ebf181</feedburner:origLink></item>
    <item>
      <title>Organizational thoughts</title>
      <description>&lt;p&gt;Ever since I ended up creating an ALT.NET group in my &lt;a href="http://spbalt.net"&gt;fair city&lt;/a&gt; I have been thinking about where I want all of this to be heading, and what I want the group to become. Currently, the activities of the group are driven by these observations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The number of seminars and public meetings related to the .NET framework is rather small.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The technical level of such meetings is typically &amp;lsquo;beginner&amp;rsquo; rather than &amp;lsquo;practitioner&amp;rsquo;, meaning that it&amp;rsquo;s not very interesting for people with work experience.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The level of people&amp;rsquo;s exposure to &lt;em&gt;new&lt;/em&gt; technology in the .NET stack is &lt;em&gt;greather&lt;/em&gt; than their exposure to existing technology. This is driven mainly by marketing concerns, and is understandable.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Consequently, the idea behind the group is to produce a .NET-oriented environment that caters to continous practice and excellence in .NET matters, and that is fit to house experienced professionals as well as people starting out (with the focus on the former). There is a lot to be said about the viability (and usefulness) of such an organization, mainly from the socio-economic point of view:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The prevalence of outsourced cost models in most cases hamper people&amp;rsquo;s professional development. In fact, with certain notable exceptions, such enterprises are &lt;em&gt;entirely incapable&lt;/em&gt; of fostering professional development because their income is based on skills declared rather than ascertained. The immediate consequence is that a &lt;em&gt;vast&lt;/em&gt; percentage of working programmers will &lt;em&gt;never&lt;/em&gt; come to our meetings, not because the level of challenge is high, but because the motivation is not there.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &amp;lsquo;worshop culture&amp;rsquo; that&amp;rsquo;s become the norm elsewhere is nonexistent. This implies that the &lt;a href="http://en.wikipedia.org/wiki/Open-space_meeting"&gt;open space&lt;/a&gt; model simply &lt;em&gt;does not work&lt;/em&gt;, because any random group of developers is unlikely to be able to self-organize and come up with a cohesive discussion plan. (I&amp;rsquo;m wrong about this in the sense that the progressive few developers might. But the .NET community is not the same as, say, a Ruby community, so YMMV, as always.)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Since the local business is essentially 90% outsourcing, it&amp;rsquo;s not interested in IT communities. This implies that the group will never have corporate sponsorship, which consequently means that the group&amp;rsquo;s profile can never be raised about &amp;lsquo;enthusiast&amp;rsquo; level. This isn&amp;rsquo;t a problem for me&amp;mdash;I&amp;rsquo;ve made a decision to never spend my own money on the group, so a zero-budget group is a perfect approach for me.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I suppose one advantage the group confers is a potential tie-in between my own company and the group. So, for example, I could provide corporate sponsorship for the group on my own terms. Because, looking at how things are right now, I doubt anyone else will.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;/ul&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/zJucd7PgBss" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/zJucd7PgBss/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/Organizational-thoughts.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=be6a0d98-6788-4cfe-8237-d2a5e17b214e</guid>
      <pubDate>Mon, 04 May 2009 19:20:00 +0300</pubDate>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=be6a0d98-6788-4cfe-8237-d2a5e17b214e</pingback:target>
      <slash:comments>0</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=be6a0d98-6788-4cfe-8237-d2a5e17b214e</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/Organizational-thoughts.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=be6a0d98-6788-4cfe-8237-d2a5e17b214e</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=be6a0d98-6788-4cfe-8237-d2a5e17b214e</feedburner:origLink></item>
    <item>
      <title>New heading styles</title>
      <description>&lt;p&gt;I have replaced post headings with images on my blog. The algorithm for making an image from text is as follows:
&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Grab heading text and turn it into a legal file name.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Render text using WPF typography and put it in a &lt;code&gt;System.Drawing.Bitmap&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Post-process the bitmap to add subpixel antialiasing.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Save the result as PNG and serve.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Funnily enough, WPF&amp;rsquo;s terrible antialiasing is a good target for ClearTypification. All I had to do is render at triple-width, distribute the energy using a five-element low-pass windowing filter (ugh, can&amp;rsquo;t beleive I just wrote that), then coalesce the bitmap back to normal width. Which gives me a good subpixel hinting result (not perfect, mind you, because it&amp;rsquo;s not grid-fitted).
&lt;/p&gt;

&lt;p&gt;The next step for this tech is to iron out the bugs and make sure some automatic subsitutions happen (like I had with SVG). Also, all bitmap-processing code has to be rewritten in C++ using OpenMP so that it is rendered a little faster. Not that it matters &amp;ndash; after all, the image is generated only once.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/9lfUKth4H_c" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/9lfUKth4H_c/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/New-heading-styles.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=c5f49e9c-bfe0-45a9-9071-9a39d57ac0c7</guid>
      <pubDate>Thu, 30 Apr 2009 14:05:00 +0300</pubDate>
      <category>wpf</category>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=c5f49e9c-bfe0-45a9-9071-9a39d57ac0c7</pingback:target>
      <slash:comments>0</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=c5f49e9c-bfe0-45a9-9071-9a39d57ac0c7</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/New-heading-styles.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=c5f49e9c-bfe0-45a9-9071-9a39d57ac0c7</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=c5f49e9c-bfe0-45a9-9071-9a39d57ac0c7</feedburner:origLink></item>
    <item>
      <title>Rendering rich typography to bitmap</title>
      <description>&lt;p&gt;In the dark ages of .NET 2.0, if you wanted OpenType text, you basically had to write your own OT engine. But in .NET 3.5, you can hijack all of the OT functionality in WPF rich typography, even if you are working with something like ASP.NET server-side image generation. Here&amp;rsquo;s how.
&lt;/p&gt;

&lt;p&gt;To begin with, you need to create the typographic elements that you are going to render:
&lt;/p&gt;

&lt;pre&gt;
Run r1 = new Run(text.Substring(0, 1))
{
  FontFamily = new FontFamily(fontName),
  FontSize = fontSize,
  FontStyle = FontStyles.Italic
};
if (char.IsLetter(text[0]))
  r1.SetValue(Typography.StandardSwashesProperty, 1);
Run r2 = new Run(text.Substring(1))
{
  FontFamily = new FontFamily(fontName),
  FontSize = fontSize
};
r2.SetValue(Typography.NumeralStyleProperty, FontNumeralStyle.OldStyle);
Paragraph p = new Paragraph {TextAlignment = TextAlignment.Left};
p.Inlines.Add(r1);
p.Inlines.Add(r2);
FlowDocument fd = new FlowDocument(p);
&lt;/pre&gt;
&lt;p&gt;Now there&amp;rsquo;a challenge: how to render a &lt;code&gt;FlowDocument&lt;/code&gt; onto a bitmap? We need to create a viewer and carry out the measure and arrange steps:
&lt;/p&gt;

&lt;pre&gt;
FlowDocumentPageViewer fdpv = new FlowDocumentPageViewer {Document = fd};
fdpv.Measure(new Size(800, 200));
fdpv.Arrange(new Rect(0, 0, 800, 200));
&lt;/pre&gt;
&lt;p&gt;The last step is to render the text onto a target bitmap:
&lt;/p&gt;

&lt;pre&gt;
RenderTargetBitmap rtb = new RenderTargetBitmap(400, 100, 72, 72, PixelFormats.Pbgra32);
rtb.Render(fdpv);
PngBitmapEncoder enc = new PngBitmapEncoder();
enc.Frames.Add(BitmapFrame.Create(rtb));
using (Stream fs = File.Create(location))
{
  enc.Save(fs);
}
&lt;/pre&gt;
&lt;p&gt;Of course, there&amp;rsquo;s a critical step missing: ClearType. Without it, all our beautiful typography is meaningless.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/GOhSMsp-Zhk" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/GOhSMsp-Zhk/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/Rendering-rich-typography-to-bitmap.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=580b7941-e5ba-4fa5-8a55-166bd3d28b21</guid>
      <pubDate>Tue, 21 Apr 2009 12:36:00 +0300</pubDate>
      <category>wpf</category>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=580b7941-e5ba-4fa5-8a55-166bd3d28b21</pingback:target>
      <slash:comments>3</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=580b7941-e5ba-4fa5-8a55-166bd3d28b21</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/Rendering-rich-typography-to-bitmap.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=580b7941-e5ba-4fa5-8a55-166bd3d28b21</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=580b7941-e5ba-4fa5-8a55-166bd3d28b21</feedburner:origLink></item>
    <item>
      <title>ClearType in Silverlight</title>
      <description>&lt;p&gt;Silverlight (and WPF) font rendering sucks, but it &lt;em&gt;is&lt;/em&gt; possible to render text with ClearType on the server side and send it to the applet. The following Silverlight app demonstrates it. Try comparing different fonts and sizes &amp;ndash; some are almost identical, but some are strikingly different. Which version is better? It&amp;rsquo;s up to you to decide.&lt;/p&gt;
&lt;div id="silverlightControlHost" align="center"&gt;
&amp;nbsp;&amp;nbsp;&lt;object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="500" height="300" style="border: 1px dashed gray"&gt;
			&lt;param name="source" value="http://nesteruk.org/projects/textsvc/ClientBin/SilverlightFontRendering.xap"/&gt;
			&lt;param name="onerror" value="onSilverlightError" /&gt;
			&lt;param name="background" value="white" /&gt;
			&lt;param name="minRuntimeVersion" value="2.0.31005.0" /&gt;
			&lt;param name="autoUpgrade" value="true" /&gt;
			&lt;a href="http://go.microsoft.com/fwlink/?LinkID=124807" style="text-decoration: none;"&gt;
     			&lt;img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style: none"/&gt;
			&lt;/a&gt;
		&lt;/object&gt;
		&lt;iframe style='visibility:hidden;height:0;width:0;border:0px'&gt;&lt;/iframe&gt;
    &lt;/div&gt;&lt;/ahref=style=&gt;&lt;/ahref=&gt;&lt;/a&gt;&lt;/paramname=&gt;&lt;/param&gt;&lt;/paramname=&gt;&lt;/param&gt;&lt;/paramname=&gt;&lt;/param&gt;&lt;/paramname=&gt;&lt;/param&gt;&lt;/param&gt;&lt;/objectdata=type=width=height=style=&gt;&lt;/objectdata=type=width=height=&gt;&lt;/objectdata=type=width=&gt;&lt;/objectdata=type=&gt;&lt;/objectdata=&gt;&lt;/object&gt;&lt;/divid=align=&gt;&lt;/divid=&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/-WbjnjM_sjw" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/-WbjnjM_sjw/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/ClearType-in-Silverlight.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=91f6f342-4a8b-4399-884d-fd3f03a603ee</guid>
      <pubDate>Sun, 05 Apr 2009 21:24:00 +0300</pubDate>
      <category>silverlight</category>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=91f6f342-4a8b-4399-884d-fd3f03a603ee</pingback:target>
      <slash:comments>4</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=91f6f342-4a8b-4399-884d-fd3f03a603ee</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/ClearType-in-Silverlight.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=91f6f342-4a8b-4399-884d-fd3f03a603ee</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=91f6f342-4a8b-4399-884d-fd3f03a603ee</feedburner:origLink></item>
    <item>
      <title>TypograFix 1.5 Released</title>
      <description>&lt;p&gt;Today I added the last of the features that I wanted to have in &lt;a href="http://code.google.com/p/typografix"&gt;TypograFix&lt;/a&gt; &amp;ndash; the ability to easily add hyperlinks by using the vertical bar &lt;code&gt;|http://like.so|&lt;/code&gt; or with text &lt;code&gt;|http://like.so like so|&lt;/code&gt;. Thus, release 1.5 has been built and rolled out via &lt;a href="http://nesteruk.org/projects/typografix"&gt;ClickOnce&lt;/a&gt;. I hope people appreciate it.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/moqbylwRRZ4" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/moqbylwRRZ4/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/TypograFix-15-Released.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=cece176e-63bd-4c0f-931a-3057fa27441e</guid>
      <pubDate>Sun, 05 Apr 2009 00:58:00 +0300</pubDate>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=cece176e-63bd-4c0f-931a-3057fa27441e</pingback:target>
      <slash:comments>0</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=cece176e-63bd-4c0f-931a-3057fa27441e</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/TypograFix-15-Released.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=cece176e-63bd-4c0f-931a-3057fa27441e</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=cece176e-63bd-4c0f-931a-3057fa27441e</feedburner:origLink></item>
    <item>
      <title>Working with SQL Server, hierarchical data and Silverlight</title>
      <description>&lt;h2&gt;Contents&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href="#Introduction"&gt;Introduction&lt;/a&gt;&lt;/li&gt;  
  &lt;li&gt;&lt;a href="#FunwithSQL"&gt;Fun with SQL&lt;/a&gt;&lt;/li&gt;  
  &lt;ul&gt;  
    &lt;li&gt;&lt;a href="#AnewUDT"&gt;A new UDT&lt;/a&gt;&lt;/li&gt;    
    &lt;li&gt;&lt;a href="#Insertion"&gt;Insertion&lt;/a&gt;&lt;/li&gt;    
    &lt;li&gt;&lt;a href="#DescendantsandAncestors"&gt;Descendants and Ancestors&lt;/a&gt;&lt;/li&gt;    
  &lt;/ul&gt;  
  &lt;li&gt;&lt;a href="#FunwithChellipornot"&gt;Fun with C#&amp;hellip; or not&lt;/a&gt;&lt;/li&gt;  
  &lt;ul&gt;  
    &lt;li&gt;&lt;a href="#BuildingaPOCO"&gt;Building a POCO&lt;/a&gt;&lt;/li&gt;    
    &lt;li&gt;&lt;a href="#Procuringthedata"&gt;Procuring the data&lt;/a&gt;&lt;/li&gt;    
    &lt;li&gt;&lt;a href="#Downloadingandusing"&gt;Downloading and using&lt;/a&gt;&lt;/li&gt;    
  &lt;/ul&gt;  
&lt;/ul&gt;
&lt;div class="selfcontained"&gt;
&lt;table border="0" cellpadding="5"&gt;
&lt;tr valign="middle"&gt;
&lt;td&gt;
&lt;img src="http://nesteruk.org/pix/vs9.png"/&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;a href="http://nesteruk.org/files/HierarchyDemo1.zip"&gt;Download source code (1.88Mb)&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h2&gt;&lt;a name="Introduction"&gt;&lt;/a&gt;Introduction&lt;/h2&gt;
&lt;p&gt;One of the new features of SQL Server 2008 is support for hierarchical data structures. These data structures can be used to store information pertaining to organization charts, online forums, network topologies, and more. This article seeks to present useful information regarding to the way you can work with hierarchical data in SQL Server.&lt;/p&gt;
&lt;p&gt;To compile and run the examples in this article, you will need Visual Studio 2008 and SQL Server 2008.&lt;/p&gt;
&lt;h2&gt;&lt;a name="FunwithSQL"&gt;&lt;/a&gt;Fun with SQL&lt;/h2&gt;
&lt;p&gt;As you may have guessed, we shall be working with data structures that help us basically build trees using SQL Server (as opposed to just &amp;lsquo;lines of data&amp;rsquo; that we&amp;rsquo;re used to). Since we&amp;rsquo;re working with trees, here are some things we need to know:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Where the root of the tree is.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Who the node&amp;rsquo;s parents and children are.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The level (depth) of a node in the tree.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ways of traversing our tree.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ways of doing indexing over the tree.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;a name="AnewUDT"&gt;&lt;/a&gt;A new UDT&lt;/h3&gt;
&lt;p&gt;In order to get all of this to work, SQL Server 2008 introduces a new UDT&lt;sup&gt;&lt;a href="#Reference1" title="A UDT is a user-defined data type. Unlike the primitive server types such as bit and int, a UDT is a CLR type, thus having typical CLR methods such as ToString()." name="BackReference1"&gt;1&lt;/a&gt;&lt;/sup&gt;, &lt;code&gt;hierarchyid&lt;/code&gt; (&lt;a href="http://msdn.microsoft.com/en-us/library/bb677290.aspx"&gt;Msdn page&lt;/a&gt;). This data type contains the &lt;em&gt;path&lt;/em&gt; from the root all the way to the node, and is thus used &lt;em&gt;in lieu&lt;/em&gt; of, say, a foreign key, when linking tree structures together. The value that SQL Server writes to &lt;code&gt;hierarchyid&lt;/code&gt; is itself unreadable (it&amp;rsquo;s made using a clever algorithm) but we can use &lt;code&gt;ToString()&lt;/code&gt; if we want to get a human-readable representation.&lt;/p&gt;
&lt;p&gt;Before we jump into C# (the scary part), let&amp;rsquo;s play a bit with good old SQL in order to get a feel for what this new feature looks like and what to do with it. Let&amp;rsquo;s imagine, for example, that we are using SQL Server to keep a hierarchical structure of help topics that can be compiled into a help application&lt;sup&gt;&lt;a href="#Reference2" title="The idea comes from Andrej Tozon&amp;rsquo;s blog entries which describe how to work with the tree control in Silverlight." name="BackReference2"&gt;2&lt;/a&gt;&lt;/sup&gt;. We begin by defining a somewhat unusual table schema&lt;sup&gt;&lt;a href="#Reference3" title="As you might have guessed, UI-driven schema creation or editing isn&amp;rsquo;t supported by tools such as Management Studio. This is due to the absense of editors (and inability to do, say a string &amp;rarr; hierarchyid conversion) as well as lack of support for computed columns." name="BackReference3"&gt;3&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;
&lt;pre&gt;
create table HelpItem
(
  Id      hierarchyid primary key clustered,
  Lvl     as Id.GetLevel(),
  ItemId  int unique,
  Name    nvarchar(32) not null,
  Content ntext
)
&lt;/pre&gt;
&lt;p&gt;Okay, that&amp;rsquo;s probably a lot different to what you&amp;rsquo;re used to, especially if, like me, your first row of (almost) every table is defined an &lt;code&gt;int identity&lt;/code&gt;. Having a &lt;code&gt;hierarchyid&lt;/code&gt; as the primary key allows us to do different types of indexing over the table, which we will discuss later. The second column, &lt;code&gt;Lvl&lt;/code&gt;, is a computed column that calls on a &lt;code&gt;GetLevel()&lt;/code&gt; method of the &lt;code&gt;hierarchyid&lt;/code&gt; type (remember it&amp;rsquo;s a CLR type)&lt;sup&gt;&lt;a href="#Reference4" title="When we come to interfacing with an ORM, we shall completely get rid of this generated column. It is only shown here as an illustration &amp;ndash; in real life, it&amp;rsquo;s probably easier to simply create generated columns as elements of a partial class that ORM frameworks make." name="BackReference4"&gt;4&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;h3&gt;&lt;a name="Insertion"&gt;&lt;/a&gt;Insertion&lt;/h3&gt;
&lt;p&gt;To appreciate both the &lt;code&gt;Id&lt;/code&gt; and &lt;code&gt;Lvl&lt;/code&gt; columns, let&amp;rsquo;s add some data to our table. This has to be done programmatically:&lt;/p&gt;
&lt;pre&gt;
insert into HelpItem
  (Id, ItemId, Name, Content)
values
  (hierarchyid::GetRoot(), 1, 'My Product', 'How to use my product')
&lt;/pre&gt;
&lt;p&gt;If you&amp;rsquo;ve never met the &lt;code&gt;::&lt;/code&gt; syntax, it&amp;rsquo;s basically used for calling class-level (static) methods inside SQL Server &amp;ndash; instance methods still use the dot notation. In the above insertion, we just specified the &lt;code&gt;hierarchyid&lt;/code&gt; of our first entry to be the root of the tree.&lt;/p&gt;
&lt;p&gt;To view the data, you must fiddle the query somewhat. Doing a typical &lt;code&gt;select *&lt;/code&gt; is useless because the &lt;code&gt;hierarchyid&lt;/code&gt; column will have the value of &lt;code&gt;0x&lt;/code&gt; in every row. Don&amp;rsquo;t ask me why (I have no idea). To get a readable value, we simply use the &lt;code&gt;ToString()&lt;/code&gt; method I mentioned earlier, and execute the following query instead:&lt;/p&gt;
&lt;pre&gt;
SELECT [Id].ToString()
      ,[Lvl]
      ,[ItemId]
      ,[Name]
      ,[Content]
  FROM [Hierarchical].[dbo].[HelpItem]
 
// here is the output:
 
Id Lvl ItemId Name       Content
-- --- ------ ---------- ---------------------
/  0   1      My Product How to use my product
&lt;/pre&gt;
&lt;p&gt;As you can see, the textual version of the root &lt;code&gt;Id&lt;/code&gt; element is a simple slash (/), and the root node has a level of &lt;code&gt;0&lt;/code&gt; (zero).&lt;/p&gt;
&lt;h3&gt;&lt;a name="DescendantsandAncestors"&gt;&lt;/a&gt;Descendants and Ancestors&lt;/h3&gt;
&lt;p&gt;We&amp;rsquo;ve managed to insert the root through some hackery, and we also ended up providing our root element with an &lt;code&gt;ItemId&lt;/code&gt; instead of auto-generating one (which can be a problem). Now, to add more elements to the hierarchy, we need to get acquainted with a new method called &lt;code&gt;GetDescendant&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Essentially, &lt;code&gt;GetDescendant&lt;/code&gt; generates the &lt;code&gt;hierarchyid&lt;/code&gt; of a new  element that is a) a descendant of the element you called it on; and b) is located between the two elements provided to &lt;code&gt;GetDescendant&lt;/code&gt; as parameters. Of course, either of the parameters can be &lt;code&gt;null&lt;/code&gt;, which means that there&amp;rsquo;s no constraint on where the element can occur.&lt;/p&gt;
&lt;p&gt;That said, let&amp;rsquo;s add a child element called &amp;lsquo;Introduction&amp;rsquo; as a child of our root element:&lt;/p&gt;
&lt;pre&gt;
insert into HelpItem
  (Id, ItemId, Name, Content)
values
  ((select Id from HelpItem where ItemId = 1).GetDescendant(null,null),
   2,
   'Introduction',
   'Some general info about our product')
&lt;/pre&gt;
&lt;p&gt;Just to reiterate, what&amp;rsquo;s happening above is that, for our new element, we chose a descendant root from the parent element. We passed two &lt;code&gt;null&lt;/code&gt; values, this making the placement of the new item unconstrained. Turning the &lt;code&gt;hierarchyid&lt;/code&gt; value of the new item yields the value &lt;code&gt;/1/&lt;/code&gt;. This piece of information is fairly useless &lt;em&gt;per se&lt;/em&gt; though, because we are mainly interested in the actual (binary) &lt;code&gt;hierarchyid&lt;/code&gt; value.&lt;/p&gt;
&lt;p&gt;In addition to being able to get at the descendant of a particular element (which is essential for random insertion), it&amp;rsquo;s also possible to get an ancestor N levels up by calling &lt;code&gt;GetAncestor(N)&lt;/code&gt; on the element you&amp;rsquo;re interested in. The result is, predictably, a &lt;code&gt;hierarchyid&lt;/code&gt; of the parent N steps up the tree, or &lt;code&gt;null&lt;/code&gt; if there aren&amp;rsquo;t that many elements up the tree.&lt;/p&gt;
&lt;p&gt;Another method available is &lt;code&gt;IsDescendantOf&lt;/code&gt;, which checks whether our &lt;code&gt;hierarchyid&lt;/code&gt; is a descendant (direct or indirect) of the &lt;code&gt;hierarchyid&lt;/code&gt; provided as parameter.&lt;/p&gt;
&lt;p&gt;All right, if you&amp;rsquo;re like me, you are probably bored with all this theory. Let&amp;rsquo;s try to make a hierarchical database and bind it to a simple Silverlight app.&lt;/p&gt;
&lt;h2&gt;&lt;a name="FunwithChellipornot"&gt;&lt;/a&gt;Fun with C#&amp;hellip; or not&lt;/h2&gt;
&lt;p&gt;It really amuses me when someone uses the phrase &lt;code&gt;modern ORM framework&lt;/code&gt; &amp;ndash; if frameworks were modern, we would have support for &lt;code&gt;hierarchyid&lt;/code&gt; in both Linq2Sql and Entity Framework. That said, it&amp;rsquo;s not the case: ORM frameworks do not support our brand new type out of the box.&lt;/p&gt;
&lt;p&gt;After playing around with trying to get a Linq2Sql T4 tempalate to play nice with &lt;code&gt;SqlHierarchyId&lt;/code&gt; (it worked, but Linq2Sql failed to agree with the idea of an &lt;code&gt;hierarchyid&lt;/code&gt; identity column), I decided to let it go at that and work without an ORM&lt;sup&gt;&lt;a href="#Reference5" title="In case you&amp;rsquo;re wondering, I looked at EF, Linq2Sql and NHContrib." name="BackReference5"&gt;5&lt;/a&gt;&lt;/sup&gt;, especially seeing how I only have one very simple table and I&amp;rsquo;m interested in working with Silverlight which, as you probably know, cannot directly use an O-R mapper anyway.&lt;/p&gt;
&lt;h3&gt;&lt;a name="BuildingaPOCO"&gt;&lt;/a&gt;Building a POCO&lt;/h3&gt;
&lt;p&gt;Seeing how we aren&amp;rsquo;t going to get an auto-generated entity class (big deal), we have to make one ourselves. This is even more appropriate if we take into account that a Silverlight app cannot use an ORM layer directly, and we end up interfacing through a web service. Here&amp;rsquo;s our service&amp;rsquo;s &lt;code&gt;HelpItem&lt;/code&gt; definition:&lt;/p&gt;
&lt;pre&gt;
[DataContract]
public class HelpItem
{
  internal SqlHierarchyId Id;
  [DataMember]
  public int ItemId;
  [DataMember]
  public string Name;
  [DataMember]
  public string Content;
  private List&amp;lt;HelpItem&amp;gt; children;
  [DataMember]
  public List&amp;lt;HelpItem&amp;gt; Children
  {
    get
    {
      return children ?? (children = new List&amp;lt;HelpItem&amp;gt;());
    }
  }
}
&lt;/pre&gt;
&lt;p&gt;This structure is tricky, and requires some explanation. Some of its elements cannot be transmitted over WCF and so are kept private &amp;ndash; for example, you cannot use the &lt;code&gt;SqlHierarchyId&lt;/code&gt; type in Silverlight anyway, so it doesn&amp;rsquo;t get its own &lt;code&gt;[DataMember]&lt;/code&gt; attribute. On the other hand, in order to transmit the &lt;em&gt;hierarchy&lt;/em&gt; we have to condense it by aggregating the items in their respective parents &amp;ndash; thus the need for a &lt;code&gt;Children&lt;/code&gt; collection (which is lazily created, to boot).&lt;/p&gt;
&lt;h3&gt;&lt;a name="Procuringthedata"&gt;&lt;/a&gt;Procuring the data&lt;/h3&gt;
&lt;p&gt;To get the data from the server, we use good old-fashioned &lt;code&gt;SqlConnection&lt;/code&gt; and &lt;code&gt;SqlCommand&lt;/code&gt; classes &amp;ndash; the way things were done when .NET was just appearing. At the moment, we define just one function, which returns all the elements as an object graph:&lt;/p&gt;
&lt;pre&gt;
[OperationContract]
public HelpItem GetHelpItems()
{
  SqlConnection dbConn = new SqlConnection(
    "Data Source=(local);Initial Catalog=Hierarchical;Integrated Security=True");
  List&amp;lt;HelpItem&amp;gt; results = new List&amp;lt;HelpItem&amp;gt;();
  try
  {
    dbConn.Open();
    SqlCommand cmd = new SqlCommand(
      "select Id.ToString(), ItemId, Name, Content from HelpItem order by Id.GetLevel()",
      dbConn);
    using (var reader = cmd.ExecuteReader())
    {
      while (reader.Read())
      {
        HelpItem i = new HelpItem
        {
          Id = SqlHierarchyId.Parse(reader.GetSqlString(0)),
          ItemId = reader.GetInt32(1),
          Name = reader.GetString(2),
          Content = reader.GetString(3)
        };
        results.Add(i);
        // make sure its parent knows
        foreach (HelpItem parent in results.Where(r =&amp;gt; r.Id.Equals(i.Id.GetAncestor(1))))
          parent.Children.Add(i);
      }
    }
  }
  finally
  {
    if (dbConn.State == System.Data.ConnectionState.Open)
      dbConn.Close();
  }
  return results.Count() &amp;gt; 0 ? results[0] : null;
}
&lt;/pre&gt;
&lt;p&gt;The only really &amp;lsquo;smart&amp;rsquo; thing we&amp;rsquo;re doing above is using LINQ and the &lt;code&gt;GetAncestor()&lt;/code&gt; method of &lt;code&gt;SqlHierarchyId&lt;/code&gt; in order to add each child to its respective parent&lt;sup&gt;&lt;a href="#Reference6" title="One interesting thing to note is the == operator doesn&amp;rsquo;t work on SqlHierarchyId &amp;ndash; at least not how one would expect. Equals() did the trick, though." name="BackReference6"&gt;6&lt;/a&gt;&lt;/sup&gt;. You&amp;rsquo;ll also note that, even though we return but a single element, this element aggregates everything else, thus yielding the whole object graph.&lt;/p&gt;
&lt;h3&gt;&lt;a name="Downloadingandusing"&gt;&lt;/a&gt;Downloading and using&lt;/h3&gt;
&lt;p&gt;Unfortunately, the POCOs we get from the service aren&amp;rsquo;t very useful on their own &amp;ndash; they have weak support for things like editing, so we copy them into corresponding client-side &lt;code&gt;HelpItem&lt;/code&gt; structures:&lt;/p&gt;
&lt;pre&gt;
private static void ProcessChildren(HelpItem orig, HelpService.HelpItem curr)
{
  foreach (HelpService.HelpItem hi in curr.Children)
  {
    HelpItem i = new HelpItem { Name = hi.Name, Content = hi.Content };
    orig.Children.Add(i);
    ProcessChildren(i, hi);
  }
}
void hsc_GetHelpItemsCompleted(object sender, GetHelpItemsCompletedEventArgs e)
{
  // convert and assign
  if (e.Result != null)
  {
    HelpItem root = new HelpItem
                      {
                        Name = e.Result.Name,
                        Content = e.Result.Content
                      };
    ProcessChildren(root, e.Result);
    items.Clear();
    items.Add(root);
  }
}
&lt;/pre&gt;
&lt;p&gt;This copying procedure lets us use better collections and more features in the entities &amp;ndash; something that will come in handy later. Meanwhile, we can use our acquired elements in the model &amp;ndash; and here&amp;rsquo;s what we get:&lt;/p&gt;
&lt;p align="center"&gt;&lt;img src="http://nesteruk.org/blog/image.axd?picture=2009%2f4%2fHierarchyClient.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;On the next iteration, we shall continue by looking at how edited tree items can be posted back to the server.&lt;/p&gt;&lt;/img&gt;&lt;/palign=&gt;&lt;/p&gt;
&lt;h2&gt;Notes&lt;/h2&gt;
&lt;ol&gt;
  &lt;li&gt;&lt;a name="Reference1"&gt;&lt;/a&gt;&lt;a href="#BackReference1" title="Back to text"&gt;^&lt;/a&gt; A UDT is a user-defined data type. Unlike the primitive server types such as &lt;code&gt;bit&lt;/code&gt; and &lt;code&gt;int&lt;/code&gt;, a UDT is a CLR type, thus having typical CLR methods such as &lt;code&gt;ToString()&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;a name="Reference2"&gt;&lt;/a&gt;&lt;a href="#BackReference2" title="Back to text"&gt;^&lt;/a&gt; The idea comes from &lt;a href="http://www.tozon.info/blogs/andrej/post/2009/01/20/Silverlight-TreeView-MVVM-and-editing-1.aspx"&gt;Andrej Tozon&amp;rsquo;s blog entries&lt;/a&gt; which describe how to work with the tree control in Silverlight.&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a name="Reference3"&gt;&lt;/a&gt;&lt;a href="#BackReference3" title="Back to text"&gt;^&lt;/a&gt; As you might have guessed, UI-driven schema creation or editing isn&amp;rsquo;t supported by tools such as Management Studio. This is due to the absense of editors (and inability to do, say a &lt;code&gt;string&lt;/code&gt; &amp;rarr; &lt;code&gt;hierarchyid&lt;/code&gt; conversion) as well as lack of support for computed columns.&lt;/li&gt;
  &lt;li&gt;&lt;a name="Reference4"&gt;&lt;/a&gt;&lt;a href="#BackReference4" title="Back to text"&gt;^&lt;/a&gt; When we come to interfacing with an ORM, we shall completely get rid of this generated column. It is only shown here as an illustration &amp;ndash; in real life, it&amp;rsquo;s probably easier to simply create generated columns as elements of a &lt;code&gt;partial&lt;/code&gt; class that ORM frameworks make.&lt;/li&gt;
  &lt;li&gt;&lt;a name="Reference5"&gt;&lt;/a&gt;&lt;a href="#BackReference5" title="Back to text"&gt;^&lt;/a&gt; In case you&amp;rsquo;re wondering, I looked at EF, Linq2Sql and NHContrib.&lt;/li&gt;
  &lt;li&gt;&lt;a name="Reference6"&gt;&lt;/a&gt;&lt;a href="#BackReference6" title="Back to text"&gt;^&lt;/a&gt; One interesting thing to note is the &lt;code&gt;==&lt;/code&gt; operator doesn&amp;rsquo;t work on &lt;code&gt;SqlHierarchyId&lt;/code&gt; &amp;ndash; at least not how one would expect. &lt;code&gt;Equals()&lt;/code&gt; did the trick, though.&lt;/li&gt;
&lt;/ol&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/g_4Q5vbnOzQ" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/g_4Q5vbnOzQ/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/Working-with-SQL-Server-hierarchical-data-and-Silverlight.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=3ac1df5f-deef-4545-8b7e-6a070ebb7000</guid>
      <pubDate>Wed, 01 Apr 2009 14:24:00 +0300</pubDate>
      <category>c#</category>
      <category>silverlight</category>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=3ac1df5f-deef-4545-8b7e-6a070ebb7000</pingback:target>
      <slash:comments>3</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=3ac1df5f-deef-4545-8b7e-6a070ebb7000</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/Working-with-SQL-Server-hierarchical-data-and-Silverlight.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=3ac1df5f-deef-4545-8b7e-6a070ebb7000</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=3ac1df5f-deef-4545-8b7e-6a070ebb7000</feedburner:origLink></item>
    <item>
      <title>F# exploration notes</title>
      <description>&lt;p&gt;Having spent some time programming in F#, I though I&amp;rsquo;d post some observations that might be useful to C# programmers.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;F# has an ambiguity with regard to the &lt;code&gt;return&lt;/code&gt; statement. It&amp;rsquo;s not required in a function, but when you are in a match block, you do need it:&lt;pre&gt;
match root.Name.ToString() with
| "rss" -&amp;gt; return ProcessAsRss(root, url)
| "atom" -&amp;gt; return ProcessAsAtom(root, url)
| _ -&amp;gt; return 0
&lt;/pre&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;F# has something against &lt;code&gt;null&lt;/code&gt;. Apparently, you cannot really have null objects without hacks. Which was a problem for me because I was trying to write&lt;pre&gt;
let id = null
&lt;/pre&gt;to use it as an output parameter in a sproc. I got so confused I had to &lt;a href="http://stackoverflow.com/questions/648086/how-to-pass-a-nullableint-into-a-stored-procedure-from-f"&gt;ask on SO&lt;/a&gt;, and ended up writing somewhat bizarre code:&lt;pre&gt;
let id = new Nullable&amp;lt;int&amp;gt;()&lt;/pre&gt;
Somewhat predictably, the &lt;code&gt;int?&lt;/code&gt; syntax is not working &amp;ndash; F# tells me that the use of a &lt;code&gt;?&lt;/code&gt; symbol after an identifier is reserved for future use.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You cannot call a function that returns something and then continue doing things. Without the &lt;code&gt;return&lt;/code&gt; statement, F# thinks that a returning function &lt;em&gt;is&lt;/em&gt; the return value. Which leads to code like the following&lt;pre&gt;
let _ = ctx.ChannelUpsert(ref id, url,
                          &amp;#8942;
                         )
&lt;/pre&gt;The underscore stores the end result, even though we don&amp;rsquo;t really care.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;One of the really useful methods for downloading from the web was &lt;em&gt;removed&lt;/em&gt; from F# in order to allow for compatibility with Silverlight and Mono. This function defines a matching pair of &lt;code&gt;Begin&lt;/code&gt; and &lt;code&gt;End&lt;/code&gt; clauses for a web request, thus allowing asynchronous operation:&lt;pre&gt;
type WebRequest with
  member x.GetResponseAsync() =
    Async.BuildPrimitive(x.BeginGetResponse, x.EndGetResponse)&lt;/pre&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;async&lt;/code&gt; keyword is really fun syntactic sugar that also exists in C# (in a way) via &lt;a href="http://www.wintellect.com/PowerThreading.aspx"&gt;PowerThreading&lt;/a&gt;&amp;rsquo;s &lt;code&gt;AsyncEnumerator&lt;/code&gt;, though this usage is somewhat more clever. Essentially, in addition to an immediate variable-definition operator &lt;code&gt;let&lt;/code&gt;, F# also has a &amp;lsquo;whenever&amp;rsquo; operator &lt;code&gt;let!&lt;/code&gt; (with an exclamation mark). This operator appears precisely at an async junction, i.e., on the left-hand side of an async call:&lt;pre&gt;
let UpsertFromUrl(url:string) =
  async {
    try
      let r = WebRequest.Create(url)
      let! resp = r.GetResponseAsync()
      use stream = resp.GetResponseStream()
      use reader = new StreamReader(stream)
      let xml = reader.ReadToEnd()
      &amp;#8942;
  }
&lt;/pre&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It seems the whole point of async ops is to fire them off on arrays (sorry, &lt;em&gt;sequences&lt;/em&gt;). It is this way in PowerThreading, and it appears this way in F#.&lt;pre&gt;
let UpdateExistingChannels =
  use ctx = new PrioryDataContext()
  ctx.Channels
  |&amp;gt; Seq.map (fun f -&amp;gt; UpsertFromUrl(f.Source))
  |&amp;gt; Async.Parallel
  |&amp;gt; Async.Run
&lt;/pre&gt;
The funny thing is: I wonder how many people will use this instead of, say, doing &lt;code&gt;Parallel.Invoke()&lt;/code&gt; instead. &amp;larr; This is C# 4 library stuff, btw. We&amp;rsquo;re not even there yet.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;F# has a &lt;code&gt;use&lt;/code&gt; keyword to match C#&amp;rsquo;s &lt;code&gt;using&lt;/code&gt;, but it&amp;rsquo;s not clear where its scope is. F# does not really delimit its scope with curly braces (exce, and indenting doesn&amp;rsquo;t help either. Figures.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Strings lose their &lt;code&gt;==&lt;/code&gt; operator, so you can no longer compare them this way. Actually, I was also comparing &lt;code&gt;string&lt;/code&gt; and &lt;code&gt;XName&lt;/code&gt; and the like, and I suspect that I might have panicked. Also &amp;ndash; and this is &lt;em&gt;annoying&lt;/em&gt; &amp;ndash; the compiler did not list the error! It just failed to compile and I had to check the build output to see what was going on. How crazy is that?!?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I managed my first F# hack!!! (err, of sorts) I was trying to do an upsert on all elements of an array, and then return the array, but whatever I did, F# was complaining that my &lt;code&gt;List.iter&lt;/code&gt; code was not to its liking. So, instead, I used &lt;code&gt;List.map&lt;/code&gt; taking the return value of my upsert sprocs and returning the length of that list. All in one statement. Witness my perfection:&lt;pre&gt;
  first.Elements() 
  |&amp;gt; Seq.filter(fun f -&amp;gt; f.Name.Equals("item"))
  |&amp;gt; Seq.map(fun f -&amp;gt; ctx.ItemUpsert(ref itemId, id, 
                                     &amp;#8942;
                                    )
  |&amp;gt; Seq.length
&lt;/pre&gt;
Programming is great!&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/d-ZwGeg6gxk" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/d-ZwGeg6gxk/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/F-exploration-notes.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=a4d93378-448b-432d-b889-23b766733575</guid>
      <pubDate>Sun, 15 Mar 2009 22:36:00 +0300</pubDate>
      <category>f#</category>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=a4d93378-448b-432d-b889-23b766733575</pingback:target>
      <slash:comments>0</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=a4d93378-448b-432d-b889-23b766733575</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/F-exploration-notes.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=a4d93378-448b-432d-b889-23b766733575</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=a4d93378-448b-432d-b889-23b766733575</feedburner:origLink></item>
    <item>
      <title>TypograFix: the end of an open-source project</title>
      <description>&lt;p&gt;I like the principle &amp;lsquo;quit while you&amp;rsquo;re ahead&amp;rsquo;. It&amp;rsquo;s indicative of a strong character, of someone showing restraint instead of attempting to get more water out of a dry well. In this vein, I have decided to cease development on my beloved &lt;a href="http://code.google.com/p/typografix"&gt;TypograFix&lt;/a&gt; project. Not because there isn&amp;rsquo;t anything interested that can be added, not because there isn&amp;rsquo;t more .NET goodness that can be exploited, not because I&amp;rsquo;ve written a Godlike application what does everything possible.&lt;/p&gt;
&lt;p&gt;I want to quit while I&amp;rsquo;m ahead.&lt;/p&gt;
&lt;p&gt;The program works. It does what I intended it to do. I use it for all my HTML work nowadays, and it covers 99% of situations. I could keep thinking of more features to add, but then I would be like those other app developers who have &lt;em&gt;already&lt;/em&gt; got a good product, but want to keep users upgrading, so they begin adding useless features that maybe 1% of their target audience will appreciate. That&amp;rsquo;s not the way I want to go with my little app.&lt;/p&gt;
&lt;p&gt;So, after release 1.5, TypograFix will be in maintenance mode, meaning if anyone &lt;a href="http://nesteruk.fogbugz.com"&gt;logs a bug&lt;/a&gt;, I&amp;rsquo;ll consider fixing it but, unless something unusual happens, development effort will be frozen.&lt;/p&gt;
&lt;p&gt;One reason open-source projects are great is that you learn lots of interesting lessons about development. For me, with this project, the lessons were as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;C# is not the best language for everything. If I had to do this all over again, I&amp;rsquo;d write it in F# or Nemerle because of their much better support for pattern matching. Since the bulk of &amp;lsquo;business logic&amp;rsquo; &lt;em&gt;is&lt;/em&gt;, in fact, pattern-matching against HTML, I could have ended up with much more readable, but also &lt;em&gt;much slower&lt;/em&gt; code. Which is okay, I don&amp;rsquo;t mind slow code for an application such as this.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Doing WPF is narrow-minded. I ended up in a situation where I wanted to use the program on a Mac. Clearly doing it in either a WinForms-esque toolkit like GTK# or doing it on the web (jQuery + web services / Silverlight) would have made more sense. Instead, I went for a heavy, badly refactorable platform. Whatever my next project is, it will most likely run on the web, just so people can access it easier. Right now, I wouldn&amp;rsquo;t even discount the idea that it will be a Flex app &amp;ndash; I&amp;rsquo;m really tempted to try something new.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The transformation function in this project has a complexity that renders TDD useless. If I had used TDD, I would have to write an &lt;em&gt;insane&lt;/em&gt; number of tests to cover eventualities that could reasonably be predicted just by looking at the code. This project is one good example of where test-driven development and &amp;ndash; especially &amp;ndash; the concept of code coverage is practically useless.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;At times, I fell victim of overengineering. I repeatedly caught myself thinking that I ended up adding a lot of superflous features (like being about to write &lt;code&gt;x^3&lt;/code&gt; and have it turned into x&amp;sup3;, that even I would hardly ever use. Many nice-to-haves got in the way of really important features that made the application easier to work with. If this was a commercial app, I&amp;rsquo;d be paying for these mistakes with market capitalization or whatnot.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ClickOnce just works, but I should have done it sooner. Since I went this &amp;lsquo;rich client&amp;rsquo; path, I should have done it this way from day 1 instead of packaging the app with an installer or (worse) as a ZIP file for &amp;lsquo;xcopy deployment&amp;rsquo;. ClickOnce is a lot easier, because people get the updated app automatically without any action on their part. If I ever do a relatively simple thick-client app again, I&amp;rsquo;d go for ClickOnce to make everyone&amp;rsquo;s life a little easier.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Leaving minor bugs in is okay. No app is perfect. I know that some features don&amp;rsquo;t work as well as I&amp;rsquo;d like, but just because it&amp;rsquo;s an open-source project doesn&amp;rsquo;t imply that I won&amp;rsquo;t do cost-benefit analysis on it. Minor bugs will either get ironed out if they become real annoyances, or they&amp;rsquo;ll stay there ignored. Either way, they aren&amp;rsquo;t something to lose sleep over.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Small is beautiful. Simplicity rules. Three large text areas, a couple of links, a disappearing property grid. That&amp;rsquo;s all you need for a sensible user interface.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Overall, TypograFix became a permanent resident on all my desktop machines, and I&amp;rsquo;m happy about the way it works to this day. I&amp;rsquo;m using it to type this blog post right now, and have many slots open for articles and things that I want to publish. One thing I realized is that, with the typography nicely done, the output result can easily be opened in Word or InDesign, should I ever feel the need to publish.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/AYGDTBIflTY" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/AYGDTBIflTY/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/TypograFix-the-end-of-an-open-source-project.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=47004a81-8deb-44e3-a50a-082ba6548c94</guid>
      <pubDate>Fri, 13 Mar 2009 22:20:00 +0300</pubDate>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=47004a81-8deb-44e3-a50a-082ba6548c94</pingback:target>
      <slash:comments>2</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=47004a81-8deb-44e3-a50a-082ba6548c94</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/TypograFix-the-end-of-an-open-source-project.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=47004a81-8deb-44e3-a50a-082ba6548c94</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=47004a81-8deb-44e3-a50a-082ba6548c94</feedburner:origLink></item>
    <item>
      <title>The employer's market?</title>
      <description>&lt;p&gt;If there&amp;rsquo;s one good thing that has come from the global economic recession, it&amp;rsquo;s the fact that things will never be the same again in the land of IT. At long last, people are being given a push to re-evaluate the way IT businesses or branches operate, and adjust the rules of the game in order to make more business sense. So, while I sit around waiting for a decent job to come by, here are some observations about how things are changing on the Russian IT market.&lt;/p&gt;
&lt;h3&gt;Telecommuting is starting to make sense&lt;/h3&gt;
&lt;p&gt;Now that cost cutting is all the rage, employers are realizing that having people work in offices full-time is not such a good idea: it&amp;rsquo;s a lot of extra costs that could be negated if you let people work from home. These costs can then be taken as savings or used to increase employee motivation in other, creative ways. Taking myself as an example, my productivity when working from home is several times greater because:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;I don&amp;rsquo;t spend extra 2 hours a day going to and from work&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;My computers are &lt;em&gt;vastly&lt;/em&gt; superior to anything any office can provide&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I have a library greater than any a Russian firm can possibly have. (then again, some don&amp;rsquo;t even have books at all)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;My working conditions are ideal. Space, adequate lighting, furniture, cooked food, everything is better&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It&amp;rsquo;s always funny when, oftentimes, I hear from some employer or other that &amp;lsquo;work from home is not real work&amp;rsquo; or that &amp;lsquo;it doesn&amp;rsquo;t count&amp;rsquo;. I hope such employers change their minds because, with the changing climate, they might be rejected more and more.&lt;/p&gt;
&lt;h3&gt;The myth of cheap programmers is disappearing&lt;/h3&gt;
&lt;p&gt;I guess there was a time &amp;lsquo;before my time&amp;rsquo; when lost of western businessmen went east with hopes of finding &amp;lsquo;great programmers, cheaply&amp;rsquo;. However, one thing that Russian companies realized is that competing on price is pointless, because countries like India will always win, especially if you compare hourly rates &amp;ndash; if you compare eventual project costs, my guess is things would be different. But that&amp;rsquo;s now really what I want to talk about.&lt;/p&gt;
&lt;p&gt;What I&amp;rsquo;m talking about is using this &amp;lsquo;economic crisis&amp;rsquo; as a pretext to hire good programmers cheaply. It doesn&amp;rsquo;t work. People just stay at home, work freelance, sit on their savings. People who came to the larger cities from smaller ones simply go back to cut living costs and wait things out. That&amp;rsquo;s not to say that employers do not try &amp;ndash; they do. I personally have been to interviews where the offered rate was 1/2 or 1/3&lt;sup&gt;rd&lt;/sup&gt; of the &amp;lsquo;expected market rate&amp;rsquo; (I&amp;rsquo;m saying &amp;lsquo;expected&amp;rsquo; because market rates &lt;em&gt;have&lt;/em&gt;, in fact, gone down). Admittedly, I did enjoy the interviews, but summarily rejected the offers &amp;ndash; something I&amp;rsquo;m hearing from other people looking for lead positions.&lt;/p&gt;
&lt;p&gt;Sure, people get hired into PM/Lead roles for measly money. I mean, someone has to take the job, right? And I&amp;rsquo;m guessing that anyone looking for a very fast &amp;lsquo;career&amp;rsquo; climb (notice I&amp;rsquo;m using quotes here) will get exactly that &amp;ndash; a difficult position with inadequate compensation. Hey, so long as everyone is happy, I won&amp;rsquo;t really complain.&lt;/p&gt;
&lt;h3&gt;Employers are more picky&lt;/h3&gt;
&lt;p&gt;There is two observations I have with regard to employment nowadays. The first is, the relationship between emloyers and employees in a hiring situation have deteriorated greatly. I used to see a situation where companies would express concrete desire to hire a particular person, entice them, etc. Not anymore! In 2009, the hiring process is strict, methodical and ruthless. And this is great!&lt;/p&gt;
&lt;p&gt;Why is it great! Because, previously, many firms had such a bad process filtering out the losers. Ask a few general questions, get a few sensible answers, hey, you&amp;rsquo;re hired! But now, nobody is spending a dollar until they are sure that that dollar is an &lt;em&gt;investment&lt;/em&gt;, and not a ballast expense. Consequently, if you&amp;rsquo;re smart, it&amp;rsquo;s becoming easier to outgun people who, despite having more experience than you, don&amp;rsquo;t know jack about technology.&lt;/p&gt;
&lt;p&gt;There is, of course, lots of stuff missing. For example, employers still do not care about community involvement. They care about projects done, but they don&amp;rsquo;t ask about talks given or papers written. This differentiating factor is taken out of the equation. Another factor is that nobody bothers to check for references. I mean, seriously, it&amp;rsquo;s just a phone call to find out whether the person quit or whether they were fired for being grossly incompetent. It seems that Russian HR simply cannot be bothered. Maybe the situation will change some day, who knows?&lt;/p&gt;
&lt;p&gt;Also, though social skills are often listed as a desire for a project management position, nobody actually asks to demonstrate in any fashion the fact that those skills are there. In fact, this is another requirement that is completely missing from the job description of most development positions, often to the subsequent detriment of collective work. Still, we aren&amp;rsquo;t at the point yet where everyone realizes it&amp;rsquo;s important.&lt;/p&gt;
&lt;h3&gt;People are more mindful of quality&lt;/h3&gt;
&lt;p&gt;It&amp;rsquo;s the same old thing reiterated: if you don&amp;rsquo;t care about quality, you may as well choose the cheapest outsourcing provider you can find. If you &lt;em&gt;do&lt;/em&gt;, it&amp;rsquo;s a lot more difficult to find the right one. In these challenging times, I find that people are becoming more concerned with the way quality is controlled during software production. TDD, continuous integration, coverage, mocking, dependency analysis &amp;ndash; these used to be words of myth that people used to shrug off just &amp;lsquo;so long as it works&amp;rsquo;. Well, now they are coming to the fore, since there&amp;rsquo;s a growing realization that a developer that isn&amp;rsquo;t constantly mindful of the testability of their software is not such a great developer after all.&lt;/p&gt;
&lt;p&gt;It has become very hard to measure quality, though, primarily because institutions like the CMM got discredited somewhat, leaving companies with few means beyond the good old chat with the customer to demonstrate that they take quality control seriously. For example, if the only code checking you do on a .NET project is with FxCop, I&amp;rsquo;m sure you&amp;rsquo;ll get laughed out of most meetings simply because nowadays, everyone realizes how awfully inadequate any single tool is. Once again, I&amp;rsquo;m loving this, because the time invested into learning about the different test/mock frameworks is going to start to pay off &amp;ndash; hopefully for me and not just for whatever company I choose to work for.&lt;/p&gt;
&lt;h3&gt;A post-crisis reshuffle is almost guaranteed&lt;/h3&gt;
&lt;p&gt;If I was desperate to find a job now, my guess is that I would accept any paycheck that would feed me and my family. Many people have done precisely that, which is why the elusive market rate has slipped (it has also slipped because of a strong dollar, but anyone smart enough would have hedged against this anyway). However, if we assume that the recession is about to end at some point (say, within a year), my guess is there would be a reckoning where companies would, once again, be able to pay top dollar (rouble, in some cases) for lead positions. And this would most likely cause the &amp;lsquo;middle management&amp;rsquo; layer of IT companies to get reshuffled once again, as large companies with renewed economic strength will headhunt the top talent and get it. That is, if things ever get back to normal.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/iwFmvsO7ezg" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/iwFmvsO7ezg/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/The-employers-market.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=c5792350-7fe1-480c-ac19-c53fe7c1f16e</guid>
      <pubDate>Thu, 12 Mar 2009 18:38:00 +0300</pubDate>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=c5792350-7fe1-480c-ac19-c53fe7c1f16e</pingback:target>
      <slash:comments>0</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=c5792350-7fe1-480c-ac19-c53fe7c1f16e</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/The-employers-market.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=c5792350-7fe1-480c-ac19-c53fe7c1f16e</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=c5792350-7fe1-480c-ac19-c53fe7c1f16e</feedburner:origLink></item>
    <item>
      <title>Bilingual programming</title>
      <description>&lt;p&gt;Sometimes, using English in coding is utterly impossible. For example, when working on a medical app, there&amp;rsquo;s no way I can translate special terms to English just so I can work with an all-English model. Funnily enough, the design process does not suffer &lt;em&gt;that&lt;/em&gt; much. For example, my abstracted Patient entity looks like this:&lt;/p&gt;
&lt;pre&gt;
&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;
&amp;lt;table name="Пациент" script="•script.xml"&amp;gt;
  &amp;lt;field name="ИндексЛечащегоВрача" type="int" filter="true"/&amp;gt;
  &amp;lt;field name="Фамилия" type="string" size="32" null="false" /&amp;gt;
  &amp;lt;field name="Имя" type="string" size="32" null="false" /&amp;gt;
  &amp;lt;field name="Отчество" type="string" size="32" null="false" /&amp;gt;
  &amp;lt;field name="ПолЖенский" type="bool" null="false" text="Пол"
         radio="true" option1="Мужской" option2="Женский"/&amp;gt;
  &amp;lt;field name="Адрес" type="string" size="128"/&amp;gt;
  &amp;lt;field name="Телефон" type="string" size="16"/&amp;gt;
  &amp;lt;field name="ДатаРождения" type="datetime"/&amp;gt;
  &amp;lt;field name="МестоРаботы" type="string" size="64"/&amp;gt;
  &amp;lt;field name="Профессия" type="string" size="64"/&amp;gt;
  &amp;lt;field name="Страховка" type="string" size="256"/&amp;gt;
&amp;lt;/table&amp;gt;
&lt;/pre&gt;
&lt;p&gt;This works so long as I keep everything in UTF-8 perpetually. Of course, I also had to alter &lt;a href="http://code.google.com/p/codegenutils"&gt;CodeGenUtils&lt;/a&gt; to handle UTF-8 but, end result it that I can manufacture Latin-Cyrillic sprocs from the model:&lt;/p&gt;
&lt;pre&gt;
/* Creates the 'Пациент' table. */
create procedure [dbo].[ПациентCreate] as
create table [dbo].[Пациент] (
  [Индекс] int identity primary key not null,
  [ИндексЛечащегоВрача] int,
  [Фамилия] nvarchar(32) not null,
  [Имя] nvarchar(32) not null,
  [Отчество] nvarchar(32) not null,
  [ПолЖенский] bit not null,
  [Адрес] nvarchar(128),
  [Телефон] nvarchar(16),
  [ДатаРождения] datetime,
  [МестоРаботы] nvarchar(64),
  [Профессия] nvarchar(64),
  [Страховка] nvarchar(256)
);
return @@error
go
&lt;/pre&gt;
&lt;p&gt;SQL Server supports Unicode names, so there&amp;rsquo;s really no problem. Firing off this stored procedure (once you get over Visual Studio&amp;rsquo;s bugs) is easy and, predictably, gets you the structure you want. Now, an ORM like the Entity Framework can grab the (cyrillic) tables easily. It won&amp;rsquo;t be able to rename tables of course, but still, it works:&lt;/p&gt;
&lt;p align="center"&gt;
&lt;img src="http://nesteruk.org/blog/image.axd?picture=2009%2f3%2fmodel.png" alt="Doctor-Patient Model" /&gt;
&lt;/p&gt;
&lt;p&gt;This is where things get tricky. Entity Framework has a bunch of inherent bugs where it expects Latin key names. However, for the most part, things work well enough. For example, binding works against Cyrillic identifiers just fine:&lt;/p&gt;
&lt;pre&gt;
&amp;lt;StackPanel Orientation="Horizontal"&amp;gt;
  &amp;lt;Label Content="Пол:"  /&amp;gt;
  &amp;lt;RadioButton Content="Мужской" 
    IsChecked="{Binding Path=ПолЖенский, Converter={StaticResource ic} }"/&amp;gt;
  &amp;lt;RadioButton Content="Женский" IsChecked="{Binding Path=ПолЖенский}"/&amp;gt;
&amp;lt;/StackPanel&amp;gt;
&lt;/pre&gt;
&lt;p&gt;The above code is, interestingly enough, auto-generated from the model. Thanks to WPF&amp;rsquo;s &lt;code&gt;WrapPanel&lt;/code&gt;, making groups of controls has never been easier:&lt;/p&gt;
&lt;p align="center"&gt;
&lt;img src="http://nesteruk.org/blog/image.axd?picture=2009%2f3%2fmapatient.png" alt="" /&gt;
&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/kh8FndPmapQ" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/kh8FndPmapQ/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/Bilingual-programming.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=b15dddb1-b817-44d5-a917-df0e0238a069</guid>
      <pubDate>Thu, 05 Mar 2009 10:41:00 +0300</pubDate>
      <category>c#</category>
      <category>wpf</category>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=b15dddb1-b817-44d5-a917-df0e0238a069</pingback:target>
      <slash:comments>0</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=b15dddb1-b817-44d5-a917-df0e0238a069</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/Bilingual-programming.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=b15dddb1-b817-44d5-a917-df0e0238a069</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=b15dddb1-b817-44d5-a917-df0e0238a069</feedburner:origLink></item>
    <item>
      <title>HTML parsing with F#</title>
      <description>&lt;p&gt;While working on &lt;a href="http://code.google.com/p/typografix"&gt;TypograFix&lt;/a&gt;, I managed to get myself into the situation where I have a massive state machine that goes through HTML one character at a time. However, due to its specifics, it starts doing look-ahead using code similar to the following:&lt;/p&gt;
&lt;pre&gt;
case '-':
  if (CannotReplace) goto default;
  // if surrounded by spaces, it's an en dash
  if (i &amp;gt; 0 &amp;amp;&amp;amp; i + 1 &amp;lt; text.Length &amp;amp;&amp;amp; text[i - 1] == ' ' &amp;amp;&amp;amp; text[i + 1] == ' ')
    hb.Append("&amp;amp;ndash;");
  else if (i + 1 &amp;lt; text.Length &amp;amp;&amp;amp; text[i + 1] == '-' &amp;amp;&amp;amp;
           (i + 2 == text.Length || text[i + 2] != '&amp;amp;'))
  {
    hb.Append("&amp;amp;mdash;");
    ++i; // ignore the second dash
  }
  else if (i + 5 &amp;lt; text.Length &amp;amp;&amp;amp;
           text[i + 1] == '-' &amp;amp;&amp;amp;
           text[i + 2] == '&amp;amp;' &amp;amp;&amp;amp;
           text[i + 3] == 'g' &amp;amp;&amp;amp;
           text[i + 4] == 't' &amp;amp;&amp;amp;
           text[i + 5] == ';')
  {
    hb.Append("&amp;amp;rarr;");
    i += 5;
  }
  else goto default;
  // same for em dash
  break;
  #endregion
&lt;/pre&gt;
&lt;p&gt;This got me thinking: apart from maybe improving the code by doing &lt;code&gt;"&amp;amp;gt;".StartsWith(text.Substring(i, 5))&lt;/code&gt; kind of code, is there anything that can &lt;em&gt;fundamentally&lt;/em&gt; improve the way the code looks? My attention turned, predictably enough, to using F# lists for string processing. (Disclaimer: using lists is probably not the best way of going through strings, but it might just be the clearest.)&lt;/p&gt;
&lt;p&gt;F# actually treats strings as sequences (think &lt;code&gt;IEnumerable&amp;lt;char&amp;gt;&lt;/code&gt;) instead of, err, lists (think &lt;code&gt;List&amp;lt;T&amp;gt;&lt;/code&gt;). Consequently, if you want to pass a string as a list, you would write&lt;/p&gt;
&lt;pre&gt;
Parse(List.of_seq "hello")
&lt;/pre&gt;
&lt;p&gt;However, for a string parsing function, it&amp;rsquo;s OK to just declare the string parameter in the constructor.&lt;/p&gt;
&lt;pre&gt;
let Proc (text : string) =
&lt;/pre&gt;
&lt;p&gt;Then, we can define some recursive processor that goes through the string one character at a time:&lt;/p&gt;
&lt;pre&gt;
let Proc (text : string) =
  let rec Other html =
    match html with
&lt;/pre&gt;
&lt;p&gt;Now comes the part with matching. Getting something like &lt;code&gt;--&amp;gt;&lt;/code&gt; is, however, a bit ugly:&lt;/p&gt;
&lt;pre&gt;
let Proc (text : string) =
  let rec Other html =
    match html with
    | '-' :: '-' :: '&amp;gt;' :: tail -&amp;gt; ("&amp;amp;rarr;" |&amp;gt; List.of_seq) @ Other tail
&lt;/pre&gt;
&lt;p&gt;It&amp;rsquo;s already looking weird, because the three parts of &lt;code&gt;--&amp;gt;&lt;/code&gt; are spread out as list elements. What I &lt;em&gt;can&lt;/em&gt; do is declare a temporary variable to store the first few elements of a list (&lt;code&gt;Seq.of_list&lt;/code&gt;) and then use &lt;code&gt;string.StartsWith&lt;/code&gt;. Which gets me more or less back to where I started.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/gAruFx0HsKo" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/gAruFx0HsKo/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/HTML-parsing-with-F.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=13be98ce-516c-43d6-94b8-4f1af3d27ada</guid>
      <pubDate>Tue, 24 Feb 2009 23:33:00 +0300</pubDate>
      <category>f#</category>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=13be98ce-516c-43d6-94b8-4f1af3d27ada</pingback:target>
      <slash:comments>0</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=13be98ce-516c-43d6-94b8-4f1af3d27ada</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/HTML-parsing-with-F.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=13be98ce-516c-43d6-94b8-4f1af3d27ada</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=13be98ce-516c-43d6-94b8-4f1af3d27ada</feedburner:origLink></item>
    <item>
      <title>Returning identity from SQL Server upsert sproc</title>
      <description>&lt;p&gt;An upsert is an update-or-insert operation realized via a stored procedure. Typically, we check the parameters against some criteria, and if the criteria match, we update an existing record. Otherwise, we create a new one. One problem I encountered is getting the primary key (&lt;code&gt;@@identity&lt;/code&gt;) of the record after it has been upserted. However, introducing a parameter (&lt;code&gt;@Id&lt;/code&gt;) seems to do the trick. Here is an example:&lt;/p&gt;
&lt;p&gt;Suppose I have a definition of an RSS channel as follows:&lt;/p&gt;
&lt;pre&gt;
create table [dbo].[Channel] (
  [Id] int identity primary key not null,
  [Title] nvarchar(128) not null,
  [Description] nvarchar(128) not null,
  [Link] nvarchar(128) not null,
  [Docs] nvarchar(128) not null,
  [Generator] nvarchar(128) not null,
  [Language] nvarchar(8) not null);
&lt;/pre&gt;
&lt;p&gt;My upsert operation would look as follows:&lt;/p&gt;
&lt;pre&gt;
create procedure [dbo].[ChannelUpsert](
  @Id int output,
  @Title nvarchar(128),
  @Description nvarchar(128),
  @Link nvarchar(128),
  @Docs nvarchar(128),
  @Generator nvarchar(128),
  @Language nvarchar(8))
as
 begin
  merge Channel as tbl
   using (select
     @Id as Id,
     @Title as Title,
     @Description as Description,
     @Link as Link,
     @Docs as Docs,
     @Generator as Generator,
     @Language as Language) as row
   on
     tbl.Link = row.Link
when not matched then
  insert(Title,Description,Link,Docs,Generator,Language)
  values(row.Title,row.Description,row.Link,row.Docs,row.Generator,row.Language)
when matched then
 update set
  @Id = tbl.Id,
  tbl.Title = row.Title,
  tbl.Description = row.Description,
  tbl.Docs = row.Docs,
  tbl.Generator = row.Generator,
  tbl.Language = row.Language
;
if @Id is null
  set @Id = SCOPE_IDENTITY()
return @Id
end
&lt;/pre&gt;
&lt;p&gt;The parameter &lt;code&gt;@Id&lt;/code&gt; is part of the sproc, tagged with the &lt;code&gt;output&lt;/code&gt; keyword, meaning that when calling from C#, you&amp;rsquo;ll need to initialize an &lt;code&gt;int?&lt;/code&gt; parameter and pass it by reference. Subsequently, we do the upsert, and if an update happens, we simply set the &lt;code&gt;@Id&lt;/code&gt; to whatever table we just updated.&lt;/p&gt;
&lt;p&gt;If towards the end the &lt;code&gt;@Id&lt;/code&gt; is &lt;code&gt;null&lt;/code&gt;, this meanins we did an &lt;code&gt;insert&lt;/code&gt; &amp;ndash; so we just assign &lt;code&gt;@Id&lt;/code&gt; to the identity value of the inserted record. We also return it from the sproc, which is somewhat unnecessary.&lt;/p&gt;
&lt;p&gt;Here is the actual usage code:&lt;/p&gt;
&lt;pre&gt;
int? id = null;
ctx.ChannelUpsert(
  ref id,
  getData(elem, "title"),
  getData(elem, "description"),
  getData(elem, "link"),
  getData(elem, "docs"),
  getData(elem, "generator"),
  getData(elem, "language"));
&lt;/pre&gt;
&lt;p&gt;Now that we have the &lt;code&gt;id&lt;/code&gt;, we can use it as a foreign key in child upsert operations.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Side note:&lt;/strong&gt; it turns out that it&amp;rsquo;s impossible to call custom sprocs (such as this one) automatically through the Entity Framework. How depressing. Well, at least Linq2SQL works.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/_aKBYD058EI" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/_aKBYD058EI/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/Returning-identity-from-SQL-Server-upsert-sproc.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=8b1f22b1-4186-455e-b9af-9c823f3e0c9d</guid>
      <pubDate>Mon, 23 Feb 2009 17:54:00 +0300</pubDate>
      <category>c#</category>
      <category>sql</category>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=8b1f22b1-4186-455e-b9af-9c823f3e0c9d</pingback:target>
      <slash:comments>0</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=8b1f22b1-4186-455e-b9af-9c823f3e0c9d</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/Returning-identity-from-SQL-Server-upsert-sproc.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=8b1f22b1-4186-455e-b9af-9c823f3e0c9d</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=8b1f22b1-4186-455e-b9af-9c823f3e0c9d</feedburner:origLink></item>
    <item>
      <title>No Comment</title>
      <description>&lt;img src="http://nesteruk.org/blog/image.axd?picture=2009%2f2%2fPatterns.jpg" alt="" /&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/4f8SJjWBzzM" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/4f8SJjWBzzM/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/No-Comment.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=d08814e0-f3ff-4075-946b-85e18b855d1f</guid>
      <pubDate>Fri, 20 Feb 2009 16:45:00 +0300</pubDate>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=d08814e0-f3ff-4075-946b-85e18b855d1f</pingback:target>
      <slash:comments>0</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=d08814e0-f3ff-4075-946b-85e18b855d1f</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/No-Comment.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=d08814e0-f3ff-4075-946b-85e18b855d1f</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=d08814e0-f3ff-4075-946b-85e18b855d1f</feedburner:origLink></item>
    <item>
      <title>Adding a Tag property to any object - without AOP</title>
      <description>&lt;p&gt;Here is a class that lets us add a &lt;code&gt;Tag&lt;/code&gt; property to any object without using AOP.&lt;/p&gt;
&lt;pre&gt;
static class ExtensionMethods
{
  private static Dictionary&amp;lt;WeakReference, object&amp;gt; tags = 
    new Dictionary&amp;lt;WeakReference, object&amp;gt;();

  public static void SetTag(this object obj, object tagValue)
  {
    Cleanup();
    var found = tags.Select(o =&amp;gt; o.Key)
      .Where(k =&amp;gt; ReferenceEquals(obj, k.Target));
    if (found.Count() &amp;gt; 0)
    {
      tags[found.Single()] = tagValue;
    }
    else
      tags[new WeakReference(obj)] = tagValue;
  }

  public static T GetTag&amp;lt;T&amp;gt;(this object obj)
  {
    return (T)tags.Where(o =&amp;gt; ReferenceEquals(o.Key.Target, obj)).First().Value;
  }

  private static void Cleanup()
  {
    var toRemove = tags.Select(o =&amp;gt; o.Key).Where(p =&amp;gt; !p.IsAlive);
    foreach (var tr in toRemove)
      tags.Remove(tr);
  }
}
&lt;/pre&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/EVZECq47Qt0" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/EVZECq47Qt0/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/Adding-a-Tag-property-to-any-object-without-AOP.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=dc3361e4-b6c2-457a-a256-75166406c280</guid>
      <pubDate>Wed, 18 Feb 2009 18:22:00 +0300</pubDate>
      <category>c#</category>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=dc3361e4-b6c2-457a-a256-75166406c280</pingback:target>
      <slash:comments>1</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=dc3361e4-b6c2-457a-a256-75166406c280</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/Adding-a-Tag-property-to-any-object-without-AOP.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=dc3361e4-b6c2-457a-a256-75166406c280</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=dc3361e4-b6c2-457a-a256-75166406c280</feedburner:origLink></item>
    <item>
      <title>Lazy loading with PostSharp</title>
      <description>&lt;p&gt;Recently I wanted to use PostSharp for some simplistic lazy loading, but ended up hitting a couple of problems along the way. It all started very well &amp;ndash; I defined an &lt;code&gt;OnFieldAccessAttribute&lt;/code&gt;, removed the field in &lt;code&gt;GetOptions()&lt;/code&gt; and overrided &lt;code&gt;OnGetValue()&lt;/code&gt; to lazily create the type. My creation code was something like the following:&lt;/p&gt;
&lt;pre&gt;
public override void OnGetValue(FieldAccessEventArgs eventArgs)
{
  if (eventArgs.StoredFieldValue == null)
    eventArgs.StoredFieldValue = Activator.CreateInstance(eventArgs.DeclaringType, args);
  eventArgs.ExposedFieldValue = eventArgs.StoredFieldValue;
}
&lt;/pre&gt;
&lt;p&gt;Big mistake. For an uninitialized field, the declaring type is &lt;code&gt;null&lt;/code&gt;. This means that it&amp;rsquo;s impossible to apply a &lt;code&gt;[LazyLoad]&lt;/code&gt; attribute, since the aspect is clueless about the type of object to lazily load. The solution &amp;ndash; passing the type :( Here it is:&lt;/p&gt;
&lt;pre&gt;
[Serializable]
class LazyLoad : OnFieldAccessAspect
{
  private readonly Type type;
  private readonly object[] args;
  public LazyLoad(Type type, params object[] arguments)
  {
    this.type = type;
    args = arguments;
  }
  public override OnFieldAccessAspectOptions GetOptions()
  {
    return OnFieldAccessAspectOptions.RemoveFieldStorage;
  }
  public override void OnGetValue(FieldAccessEventArgs eventArgs)
  {
    if (eventArgs.StoredFieldValue == null)
      eventArgs.StoredFieldValue = Activator.CreateInstance(type, args);
    eventArgs.ExposedFieldValue = eventArgs.StoredFieldValue;
  }
}
&lt;/pre&gt;
&lt;p&gt;This takes care of both the type to create and the arguments, so it can be used as follows:&lt;/p&gt;
&lt;pre&gt;
class B
{
  public B()
  {
  }
  [LazyLoad(typeof(A))]
  public A A;
}
&lt;/pre&gt;
&lt;p&gt;You don&amp;rsquo;t want to know what happend if A is a value type &amp;ndash; really, you don&amp;rsquo;t. But the above code works, and lazy-loads the A variable only when accessed. So far so good, right? Well, yes, except there is a problem: sometimes I want to lazy-load a member, passing &lt;code&gt;this&lt;/code&gt; into the constructor. I could make this super-complicated by overloading aspect constructors, but I decided to create a new aspect instead:&lt;/p&gt;
&lt;pre&gt;
[Serializable]
class LazyLoadWithThis : OnFieldAccessAspect
{
  private readonly Type type;
  public LazyLoadWithThis(Type type)
  {
    this.type = type;
  }
  public override OnFieldAccessAspectOptions GetOptions()
  {
    return OnFieldAccessAspectOptions.RemoveFieldStorage;
  }
  public override void OnGetValue(FieldAccessEventArgs eventArgs)
  {
    if (eventArgs.StoredFieldValue == null)
      eventArgs.StoredFieldValue = Activator.CreateInstance(type, new[] {eventArgs.Instance});
    eventArgs.ExposedFieldValue = eventArgs.StoredFieldValue;
  }
}
&lt;/pre&gt;
&lt;p&gt;There. That covers &lt;em&gt;my&lt;/em&gt; needs. However, since there&amp;rsquo;s a myriad of &lt;code&gt;Activator.CreateInstance()&lt;/code&gt; overloads, there&amp;rsquo;s probably a lot more one can do with lazy-loading aspects. Shame about the (somewhat) ugly syntax though &amp;ndash; but then again, this lets you lazy-load polymorphically, if that&amp;rsquo;s your cup of tea. And I &lt;em&gt;strongly&lt;/em&gt; suspect that lazy-loading semantics are domain-specific in most cases (they certainly are in my projects), so the above is only an example.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/S35CzsC_8xM" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/S35CzsC_8xM/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/Lazy-loading-with-PostSharp.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=ccf573b9-a678-46e6-acce-cb0a512123b6</guid>
      <pubDate>Wed, 18 Feb 2009 10:05:00 +0300</pubDate>
      <category>aop</category>
      <category>c#</category>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=ccf573b9-a678-46e6-acce-cb0a512123b6</pingback:target>
      <slash:comments>1</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=ccf573b9-a678-46e6-acce-cb0a512123b6</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/Lazy-loading-with-PostSharp.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=ccf573b9-a678-46e6-acce-cb0a512123b6</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=ccf573b9-a678-46e6-acce-cb0a512123b6</feedburner:origLink></item>
    <item>
      <title>Cross-thread collection updates in WPF</title>
      <description>&lt;p&gt;It&amp;rsquo;s often very tempting to write your own version of &lt;code&gt;ObservableCollection&lt;/code&gt; to accomodate cross-thread calls. However, this is not a very good idea, because you never know what your usage scenario might be. For example, I had to create a binding to an &lt;code&gt;ObservableCollection&lt;/code&gt; with set semantics (i.e., duplicates are not allowed) in order to get SQL Server Management Objects to periodically scan the network for SQL Server instances. Even though I already had a &lt;code&gt;MyObservableCollection&lt;/code&gt; class ready, it didn&amp;rsquo;t work for me because I needed to get a &lt;em&gt;result&lt;/em&gt; from the conditional insert method, indicating whether it actually succeeded.&lt;/p&gt;
&lt;p&gt;As always, I got tempted to use the PostSharp aspect to make the call async and to handle errors. However, what I ended up doing is isolating my async code from the code that still had to happen in the UI thread. The end result &amp;ndash; another rather ugly call on the &lt;code&gt;Dispatcher&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;
[WorkerThread, ExceptionDialog]
private void LoadDatabases()
{
  bool added;
  do
  {
    added = false;
    foreach (string db in State.FindDatabases())
    {
      added = (bool)Dispatcher.Invoke(
        (Func&amp;lt;string, bool&amp;gt;) delegate(string s)
        {
          bool a = false;
          if (!Databases.Contains(s))
          {
            a = true;
            Databases.Add(s);
          }
          return a;
        }, db);
      }
  } while (added);
}
&lt;/pre&gt;
&lt;p&gt;Code like this makes me want to be an Erlang programmer.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/8vcK_NYfUo4" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/8vcK_NYfUo4/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/Cross-thread-collection-updates-in-WPF.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=7bb11ffd-5338-48b3-a9e2-6a1ce3e30085</guid>
      <pubDate>Tue, 17 Feb 2009 02:50:00 +0300</pubDate>
      <category>aop</category>
      <category>c#</category>
      <category>wpf</category>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=7bb11ffd-5338-48b3-a9e2-6a1ce3e30085</pingback:target>
      <slash:comments>0</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=7bb11ffd-5338-48b3-a9e2-6a1ce3e30085</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/Cross-thread-collection-updates-in-WPF.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=7bb11ffd-5338-48b3-a9e2-6a1ce3e30085</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=7bb11ffd-5338-48b3-a9e2-6a1ce3e30085</feedburner:origLink></item>
    <item>
      <title>AOP-based reporting of exceptions in separate threads</title>
      <description>&lt;p&gt;The &lt;code&gt;WorkerThread&lt;/code&gt; aspect is a really cheap way of running a method asynchronously in the thread pool. Sure, you don&amp;rsquo;t get to pick priority and such, but for a general-puspose background task, it&amp;rsquo;s perfect:&lt;/p&gt;
&lt;pre&gt;
[Serializable]
public class WorkerThreadAttribute : OnMethodInvocationAspect
{
  public override void OnInvocation(MethodInvocationEventArgs eventArgs)
  {
    ThreadPool.QueueUserWorkItem(state =&amp;gt; eventArgs.Proceed());
  }
}
&lt;/pre&gt;
&lt;p&gt;There&amp;rsquo;s one problem with this method, though &amp;ndash; it becomes more difficult to catch exceptions. For example, if you have a VS add-in throwing an exception on a separate thread, VS itself will not catch it and your add-in will crash. The solution? Another aspect:&lt;/p&gt;
&lt;pre&gt;
[Serializable]
public class ExceptionDialogAttribute : OnExceptionAspect
{
  public override void OnException(MethodExecutionEventArgs eventArgs)
  {
    ExceptionMessageBox emb = new ExceptionMessageBox(
      eventArgs.Exception,
      ExceptionMessageBoxButtons.OK,
      ExceptionMessageBoxSymbol.Error);
    emb.Show(null);
  }
}
&lt;/pre&gt;
&lt;p&gt;Rather than using a boring &lt;code&gt;MessageBox&lt;/code&gt; to report the exception, I went for a richer user interface &amp;ndash; namely, the &lt;code&gt;ExceptionMessageBox&lt;/code&gt; that comes with SQL Server. Just what the doctor ordered.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/Tzn6NFhhQOU" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/Tzn6NFhhQOU/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/AOP-based-reporting-of-exceptions-in-separate-threads.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=fec71f2d-6b19-4436-9f1c-7d8237aa7bf2</guid>
      <pubDate>Sun, 15 Feb 2009 22:35:00 +0300</pubDate>
      <category>aop</category>
      <category>c#</category>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=fec71f2d-6b19-4436-9f1c-7d8237aa7bf2</pingback:target>
      <slash:comments>1</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=fec71f2d-6b19-4436-9f1c-7d8237aa7bf2</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/AOP-based-reporting-of-exceptions-in-separate-threads.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=fec71f2d-6b19-4436-9f1c-7d8237aa7bf2</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=fec71f2d-6b19-4436-9f1c-7d8237aa7bf2</feedburner:origLink></item>
    <item>
      <title>Fun with Wait and Pulse</title>
      <description>&lt;p&gt;Anyone who has used Microsoft Project for time tracking is probably familiar with terms like Finish-to-Shart and Start-to-Start. For example, in a Waterfall model, we say that Requirements have to &amp;lsquo;finish&amp;rsquo; (i.e., we must have them) before Coding starts.&lt;/p&gt;
&lt;p&gt;The same idea also appears in multithreading &amp;ndash; having a process begin only when another has started or is finished. In an ideal world, such problems in C# would be resolved using a clear, sensible API. Unfortunately, even waiting on several processes to complete is not easy. Here&amp;rsquo;s an illustration:&lt;/p&gt;
&lt;pre&gt;
ThreadStart delA = a;
ThreadStart delB = b;
IAsyncResult arA = delA.BeginInvoke(null, null);
IAsyncResult arB = delB.BeginInvoke(null, null);
// no, you cannot have a pony
WaitHandle.WaitAll(new[]{ arA.AsyncWaitHandle, arB.AsyncWaitHandle});
&lt;/pre&gt;
&lt;p&gt;That&amp;rsquo;s right &amp;ndash; the neat API features such as &lt;code&gt;WaitAll()&lt;/code&gt; are unusable simply because it only works under &lt;code&gt;[MtaThread]&lt;/code&gt;, which ruins the fun for far too many people to be useful.&lt;/p&gt;
&lt;h3&gt;Pulse &amp;amp; Wait&lt;/h3&gt;
&lt;p&gt;The static methods &lt;code&gt;Pulse()&lt;/code&gt; and &lt;code&gt;Wait()&lt;/code&gt; of the &lt;code&gt;Minitor&lt;/code&gt; class are a solution to our problem of waiting on many concurrent operations to complete. That covers the finish-to-start scenario, but these mechanisms work for the start-to-start scenario, too. Let&amp;rsquo;s see how.&lt;/p&gt;
&lt;p&gt;Imagine you&amp;rsquo;re making breakfast, consisting of jam on toast and a cup of tea. Now, toasting bread and making tea are async operations; you can only try to take the jam out once you&amp;rsquo;ve started toasting the bread; you can only have breakfast when you&amp;rsquo;ve got jam on toast and a cup of tea. Here&amp;rsquo;s a graphic representation:&lt;/p&gt;
&lt;p align="center"&gt;&lt;img src="http://nesteruk.org/blog/image.axd?picture=2009%2f2%2fMakingBreakfast.png" title="Making breakfast DSL screenshot"/&gt;&lt;/p&gt;
&lt;p&gt;Just in case you haven&amp;rsquo;t guessed, solid lines are finish-to-start ones, while the dashed line is start-to-start. So how would code for such a scenario look? Well, the first thing you must realize with &lt;code&gt;Wait()&lt;/code&gt; and &lt;code&gt;Pulse()&lt;/code&gt; is that &lt;strong&gt;every operation that waits on something has a lock&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;
private readonly object MakeSandwichLock = new object();
private readonly object EatBreakfastLock = new object();
private readonly object GetJamLock = new object();
&lt;/pre&gt;
&lt;p&gt;Now, pay attention, here&amp;rsquo;s the second part of the puzzle: &lt;strong&gt;every operation that someone waits on has a &lt;code&gt;bool&lt;/code&gt; indicating whether it is done&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;
private bool MakeTeaIsDone;
private bool ToastBreadIsDone;
private bool GetJamIsDone;
private bool MakeSandwichIsDone;
&lt;/pre&gt;
&lt;p&gt;Okay, if you look at the diagram, the two parts of nomenclature I just mentioned should be obvious. &lt;code&gt;MakeSandwich&lt;/code&gt;, &lt;code&gt;EatBreakfast&lt;/code&gt; and &lt;code&gt;GetJam&lt;/code&gt; all wait on someone &amp;ndash; although &lt;code&gt;GetJam&lt;/code&gt; does a &amp;lsquo;soft wait&amp;rsquo; because it waits for something to &lt;em&gt;start&lt;/em&gt; and not finish. Then each function that is waited upon got a &lt;code&gt;bool&lt;/code&gt; flag to indicate whether it is done. Hey, we need some indicator, right?&lt;/p&gt;
&lt;p&gt;Now here&amp;rsquo;s the third part of the puzzle: &lt;strong&gt;both finish-to-shart and start-to-start operations are enforced by a)locking on your lock; b) doing a &lt;code&gt;Monitor.Wait()&lt;/code&gt; if the combination of boolean flags is unsatisfactory&lt;/strong&gt;. Here&amp;rsquo;s some code for actually eating the breakfast:&lt;/p&gt;
&lt;pre&gt;
protected internal void EatBreakfast()
{
  lock(EatBreakfastLock)
    if(!(MakeTeaIsDone &amp;amp;&amp;amp; MakeSandwichIsDone))
      Monitor.Wait(EatBreakfastLock);
  EatBreakfastImpl();
}
&lt;/pre&gt;
&lt;p&gt;Just to reiterate: to get to eat breakfast, we a)lock on the breakfast lock; and b)wait on that same lock if we cannot proceed yet. Okay, we&amp;rsquo;re almost there &amp;ndash; all we need to know is when to actually set those boolean flags and &lt;code&gt;Pulse()&lt;/code&gt;. Well, this depends: if you are doing a start-to-start, you do it at the start of the method; otherwise, do it at the end. Do what? Well, &lt;strong&gt;to inform someone you&amp;rsquo;re done, lock on the &lt;em&gt;target&lt;/em&gt; lock (i.e., on the lock of someone waiting on you), then set your &lt;code&gt;Done&lt;/code&gt; boolean to true, then &lt;code&gt;Pulse()&lt;/code&gt;&lt;/strong&gt;. For example, after tea is ready, here&amp;rsquo;s how to tell the &lt;code&gt;EatBreakfast&lt;/code&gt; method that it can (theoretically) proceed:&lt;/p&gt;
&lt;pre&gt;
protected internal void MakeTea()
{
  MakeTeaImpl();
  lock(EatBreakfastLock)
  {
    MakeTeaIsDone = true;
    Monitor.PulseAll(EatBreakfastLock);
  }
}
&lt;/pre&gt;
&lt;h3&gt;Ordering&lt;/h3&gt;
&lt;p&gt;Before we move on, here&amp;rsquo;s the whole &lt;code&gt;Breakfast&lt;/code&gt; class (without the &lt;code&gt;Impl()&lt;/code&gt; methods, of course):&lt;/p&gt;
&lt;pre&gt;
partial class Breakfast
{
  private readonly object MakeSandwichLock = new object();
  private readonly object EatBreakfastLock = new object();
  private readonly object GetJamLock = new object();
  private bool MakeTeaIsDone;
  private bool ToastBreadIsDone;
  private bool GetJamIsDone;
  private bool MakeSandwichIsDone;
  private bool ToastBreadStarted;
  protected internal void MakeTea()
  {
    MakeTeaImpl();
    lock(EatBreakfastLock)
    {
      MakeTeaIsDone = true;
      Monitor.PulseAll(EatBreakfastLock);
    }
  }
  protected internal void ToastBread()
  {
    lock(GetJamLock)
    {
      ToastBreadIsDone = true;
      Monitor.PulseAll(GetJamLock);
    }
    ToastBreadImpl();
    lock(MakeSandwichLock)
    {
      ToastBreadIsDone = true;
      Monitor.PulseAll(MakeSandwichLock);
    }
  }
  protected internal void GetJam()
  {
    lock(GetJamLock)
      if(!(ToastBreadStarted))
        Monitor.Wait(GetJamLock);
    GetJamImpl();
    lock(MakeSandwichLock)
    {
      GetJamIsDone = true;
      Monitor.PulseAll(MakeSandwichLock);
    }
  }
  protected internal void MakeSandwich()
  {
    lock(MakeSandwichLock)
      if(!(ToastBreadIsDone &amp;amp;&amp;amp; GetJamIsDone))
        Monitor.Wait(MakeSandwichLock);
    MakeSandwichImpl();
    lock(EatBreakfastLock)
    {
      MakeSandwichIsDone = true;
      Monitor.PulseAll(EatBreakfastLock);
    }
  }
  protected internal void EatBreakfast()
  {
    lock(EatBreakfastLock)
      if(!(MakeTeaIsDone &amp;amp;&amp;amp; MakeSandwichIsDone))
        Monitor.Wait(EatBreakfastLock);
    EatBreakfastImpl();
  }
}
&lt;/pre&gt;
&lt;p&gt;So, how does this monstrosity get fired off? Well, here&amp;rsquo;s one possibility:&lt;/p&gt;
&lt;pre&gt;
ThreadStart[] ops = new ThreadStart[] {
  MakeTea,
  GetJam,
  ToastBread,
  MakeSandwich,
  EatBreakfast };
foreach (ThreadStart op in ops)
  op.BeginInvoke(null, null);
&lt;/pre&gt;
&lt;p&gt;There&amp;rsquo;s one caveat with all of this: what if we had &lt;code&gt;ToastBread&lt;/code&gt; before &lt;code&gt;GetJam&lt;/code&gt; in the list? That&amp;rsquo;s right &amp;ndash; you would have a hanging application. It&amp;rsquo;s important to remember that &lt;strong&gt;&lt;code&gt;Pulse()&lt;/code&gt; is only useful is someone is &lt;code&gt;Wait()&lt;/code&gt;ing on it&lt;/strong&gt;. If you cause a situation where &lt;code&gt;Pulse()&lt;/code&gt; is fired before the &lt;code&gt;Wait()&lt;/code&gt;ing code is running, you&amp;rsquo;re in trouble. Luckily, it&amp;rsquo;s a fairly obvious mistake that you&amp;rsquo;re likely to spot even if you&amp;rsquo;re not into unit tests.&lt;/p&gt;
&lt;h3&gt;In Closing&lt;/h3&gt;
&lt;p&gt;I don&amp;rsquo;t seriously recommend anyone writing code like the one above &amp;ndash; in fact, the above picture and code come from a DSL that facilitates P&amp;amp;W-based asynchronous design and a lot more.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/o0Y0BpETVLE" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/o0Y0BpETVLE/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/Fun-with-Wait-and-Pulse.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=890db6e3-ac11-409d-8455-0850497e08ef</guid>
      <pubDate>Tue, 03 Feb 2009 02:31:00 +0300</pubDate>
      <category>c#</category>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=890db6e3-ac11-409d-8455-0850497e08ef</pingback:target>
      <slash:comments>1</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=890db6e3-ac11-409d-8455-0850497e08ef</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/Fun-with-Wait-and-Pulse.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=890db6e3-ac11-409d-8455-0850497e08ef</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=890db6e3-ac11-409d-8455-0850497e08ef</feedburner:origLink></item>
    <item>
      <title>Cheap way of speeding up Visual Studio I/O</title>
      <description>&lt;p&gt;Visual Studio loves file I/O. It really, really does, and it cares very little about caching and the like. What this means is that, when you open a solution file, it &lt;em&gt;always&lt;/em&gt; reads it from disk. Which means that the speed of operation when generating lots of files (e.g., via T4 transformations) is typically atrocious. The fact that file I/O in VS does not appear to be multithreaded is another hindrance. In short, it&amp;rsquo;s a mess.&lt;/p&gt;
&lt;p&gt;So here&amp;rsquo;s a stupid solution that I&amp;rsquo;ve been using for ages with excellent results &amp;ndash; &lt;strong&gt;make a RAM disk&lt;/strong&gt;! By sacrificing a small amount of RAM (I give it 128Mb), you can move your whole solution into RAM, where I/O speeds are far greater &amp;ndash; &lt;em&gt;noticeably&lt;/em&gt; greater when working with Visual Studio.&lt;/p&gt;
&lt;p&gt;To get a RAM disk working, I followed advice on &lt;a href="http://www.fiveanddime.net/windows-vista-notes/ram-disk-howto.html"&gt;this page&lt;/a&gt; to the letter, and got it all set up under Vista. Then, when I need to, I simply snapshot my Subversion projects onto the RAM drive and do my work. If the stuff I work on is sensitive, I can even erase the RAM drive after work &amp;ndash; committing beforehand, of course.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/8Y6PwJWU-BQ" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/8Y6PwJWU-BQ/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/Cheap-way-of-speeding-up-Visual-Studio-IO.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=85dbfc04-62ab-4871-8560-cd6fd1120140</guid>
      <pubDate>Wed, 28 Jan 2009 21:06:00 +0300</pubDate>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=85dbfc04-62ab-4871-8560-cd6fd1120140</pingback:target>
      <slash:comments>17</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=85dbfc04-62ab-4871-8560-cd6fd1120140</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/Cheap-way-of-speeding-up-Visual-Studio-IO.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=85dbfc04-62ab-4871-8560-cd6fd1120140</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=85dbfc04-62ab-4871-8560-cd6fd1120140</feedburner:origLink></item>
    <item>
      <title>Typographic reflections</title>
      <description>&lt;p&gt;Having spent far too much time working on &lt;a href="http://code.google.com/p/typografix"&gt;TypograFix&lt;/a&gt;, I now have a few moments to recount my experiences &amp;ndash; in particular, the useful things I&amp;rsquo;ve learned.&lt;/p&gt;
&lt;h3&gt;AOP and Cross-Thread Calls&lt;/h3&gt;
&lt;p&gt;First, I finally added AOP support to the project. I&amp;rsquo;m not using AOP for validation, since there&amp;rsquo;s very little, but I &lt;em&gt;am&lt;/em&gt; using two AOP features to drive the app. The first is a &lt;code&gt;[WorkerThread]&lt;/code&gt; attribute, which causes a function to be called in a separate thread. It&amp;rsquo;s probably the simplest, most brainless aspect you can think of:&lt;/p&gt;
&lt;pre&gt;
/// &amp;lt;summary&amp;gt;
/// Makes the method run async.
/// &amp;lt;/summary&amp;gt;
[Serializable]
public class WorkerThreadAttribute : OnMethodInvocationAspect
{
  public override void OnInvocation(MethodInvocationEventArgs eventArgs)
  {
    ThreadPool.QueueUserWorkItem(state =&amp;gt; eventArgs.Proceed());
  }
}
&lt;/pre&gt;
&lt;p&gt;What surprised me was that this attribute worked surprisingly well &amp;ndash; I just put it in front of the &lt;code&gt;DoUpdate()&lt;/code&gt; function, and it started running async, fired every 5 seconds by a timer. The only thing that annoys me is that the WinForms &lt;code&gt;WebBrowser&lt;/code&gt; control makes a clicking sound whenever I update and, at the moment, I don&amp;rsquo;t have a clue how to remove it.&lt;/p&gt;
&lt;p&gt;My application uses both WPF and WinForms controls (you&amp;rsquo;ve guessed it &amp;ndash; the &lt;code&gt;WebBrowser&lt;/code&gt; control), so having this attribute implies that I have to do those ugly cross-thread calls. One &amp;lsquo;gotcha&amp;rsquo; I got from this is that not only does &lt;em&gt;setting&lt;/em&gt; a WPF control property require the use of a &lt;code&gt;Dispatcher&lt;/code&gt;, but &lt;em&gt;getting&lt;/em&gt; the property requires one too (which makes sense in retrospect, I guess). This led me to write the following, slightly bizarre, piece of code:&lt;/p&gt;
&lt;pre&gt;
string text = (string)tbOut.Dispatcher.Invoke((Func&amp;lt;string&amp;gt;) delegate
{
  ConversionStatus cs;
  string msg;
  tbOut.Text = Generator.Generate(
    tbIn.Text,
    App.ConversionOptions,
    5000,
    true,
    out cs,
    out msg);
  ConversionMessage = msg;
  Status = cs;
  return tbOut.Text;
});
&lt;/pre&gt;
&lt;p&gt;This is the first time I&amp;rsquo;ve done a &lt;code&gt;return&lt;/code&gt; from an &lt;code&gt;Invoke()&lt;/code&gt; on a delegate &amp;ndash; and is probably the last time, since I don&amp;rsquo;t like the notation. I think this piece of code is somewhat hard to read, and is confusing to anyone but me.&lt;/p&gt;
&lt;p&gt;The second AOP attribute I used is &lt;code&gt;[INotifyPropertyChanged]&lt;/code&gt;, which adds support for change notifications to a class in just one line of code (instead of all that event and firing stuff). Annoyingly enough, the PostSharp sample had a &lt;em&gt;bug&lt;/em&gt; which took me some time to track down, but I got it working in the end. The attribute implementation itself weighs in at 226 lines of code, which is quite a bit &amp;ndash; but then the functionality is so useful &amp;ndash; it works on auto-properties just fine!&lt;/p&gt;
&lt;p&gt;The only real snag I had (again, due to inexperience) was a question &amp;ndash; how do I cast an object to an &lt;code&gt;INotifyPropertyChanged&lt;/code&gt; interface if it doesn&amp;rsquo;t implement this interface at compile-time? Luckily, the solution is really simple &amp;ndash; a double cast via &lt;code&gt;object&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;
INotifyPropertyChanged npc = (INotifyPropertyChanged)(object)App.ConversionOptions;
&lt;/pre&gt;
&lt;p&gt;Incidentally, PostSharp does provide a generic method &lt;code&gt;Post.Cast&amp;lt;&amp;gt;&lt;/code&gt; to do this, but I had some trouble with it, so I&amp;rsquo;m sticking to the double cast for now. You wouldn&amp;rsquo;t beleive the kinds of options I tried though! For example, I tried to do a &lt;code&gt;GetInterfaces()&lt;/code&gt; at runtime to find the object having an &lt;code&gt;INotifyPropertyChanged&lt;/code&gt; interface, but to my amazement, &lt;em&gt;it didn&amp;rsquo;t&lt;/em&gt;, probably because it was extended by PostSharp&amp;rsquo;s own interface wrapper.&lt;/p&gt;
&lt;h3&gt;Strong Names&lt;/h3&gt;
&lt;p&gt;Rule of thumb for library makers: provide a strong name. This is something that was missing from AOP-based validation package (which I later decided not to use). Basically, if you make a reusable library and don&amp;rsquo;t provide a strong name, I can&amp;rsquo;t use it in strongly-named assemblies myself. And even if I have your source code, I&amp;rsquo;m a bit too lazy to provide a strong name myself.&lt;/p&gt;
&lt;p&gt;Why? Because, apart from having to generate the &lt;code&gt;snk&lt;/code&gt; or &lt;code&gt;pfx&lt;/code&gt; file, I also have to get the public key and update all the &lt;code&gt;[InternalsVisibleTo]&lt;/code&gt; attributes &amp;ndash; not in my solution, but in the 3&lt;sup&gt;rd&lt;/sup&gt; party library one! How crazy is that?&lt;/p&gt;
&lt;p&gt;This is &lt;em&gt;definitely&lt;/em&gt; something to remember for the future.&lt;/p&gt;
&lt;h3&gt;Maintainability&lt;/h3&gt;
&lt;p&gt;I finally had a change to take a look at the metrics that VSTS gives me for the transformation function. Needless to say, the situation is dire:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;195 lines of code&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Class coupling of 15&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cyclomatic complexity of 192 (!!!)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Maintainability index of 0 (zero)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If I was managing a project and someone wrote this, I&amp;rsquo;d ask them to refactor it. Clearly, having a massive state machine in one function is not the best way to go, especially seeing how I have conditionals everywhere &amp;ndash; that&amp;rsquo;s right, I&amp;rsquo;m using the evil &lt;code&gt;goto&lt;/code&gt; statement &lt;em&gt;all over the place&lt;/em&gt;, because within &lt;code&gt;switch&lt;/code&gt; statements, the &lt;code&gt;goto&lt;/code&gt; instruction is capable of jumping to the &lt;code&gt;default&lt;/code&gt; label &amp;ndash; a situation that happens far too often when a match against an expected condition fails.&lt;/p&gt;
&lt;p&gt;Although I cannot refactor the method manually, it might be possible to do it with programmatic means &amp;ndash; some sort of static transformation can turn this huge &lt;code&gt;switch&lt;/code&gt; monstrosity into a series of separate functions (perhaps in a nested class) or even a WF or some sort of DSL. At the moment, I&amp;rsquo;m happy with the code, so I&amp;rsquo;m not bothered that much. But it&amp;rsquo;s something I might do later.&lt;/p&gt;
&lt;h3&gt;Cross-Platform Plans&lt;/h3&gt;
&lt;p&gt;Since I spend a small amount of time on a Mac, I&amp;rsquo;m thinking of transforming this application into something that can run on either Mono, ASP.NET (via AJAX, of course), or Silverlight. (I wish I could consider AIR, too, but I doubt it can understand C#.) The idea is that &lt;em&gt;anyone&lt;/em&gt; can use my script to prepare documents for publication.&lt;/p&gt;
&lt;p&gt;On a side note, I finally managed to do a &lt;a href="http://nesteruk.org/screencasts/typografix"&gt;screencast&lt;/a&gt; for the program, so anyone who wants to get some web-based typographic goodness can take a look at the program in action. Admittedly, it&amp;rsquo;s not very exciting, but then again, what excites me is the fact that I&amp;rsquo;m using &lt;em&gt;my own program&lt;/em&gt; for pretty much all the HTML publication I do. Including this blog post.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/rmzTartGFpo" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/rmzTartGFpo/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/Typografic-reclections.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=4d71a610-203f-4ae5-90d5-e894d56c3403</guid>
      <pubDate>Wed, 28 Jan 2009 02:48:00 +0300</pubDate>
      <category>c#</category>
      <category>aop</category>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=4d71a610-203f-4ae5-90d5-e894d56c3403</pingback:target>
      <slash:comments>0</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=4d71a610-203f-4ae5-90d5-e894d56c3403</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/Typografic-reclections.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=4d71a610-203f-4ae5-90d5-e894d56c3403</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=4d71a610-203f-4ae5-90d5-e894d56c3403</feedburner:origLink></item>
    <item>
      <title>Diversification</title>
      <description>&lt;p&gt;This is a new blog, which has arisen as a result of restructuring of my own domain, as well as my desire to leave the main one (mindstudies.org) where it is, and maybe enhance it somewhat. My stuff must go, and now it&amp;rsquo;s all completely separate, though I will be leaving the old blog where it is.&lt;/p&gt;
&lt;p&gt;That was number one. The second thing I want to announce (to whom, I wonder), is the fact that after two open-source projects written in C# and WPF (I&amp;rsquo;m talking about the &lt;a href="http://code.google.com/p/mmlsharp"&gt;MathML &amp;rarr; C# Converter&lt;/a&gt; and &lt;a href="http://code.google.com/p/typografix"&gt;TypograFix&lt;/a&gt;, which I use to type all my stuff now), I decided that my next widget, whatever it happens to be, will be done in a different language. Which one? Well, it will most likely be F#, but I&amp;rsquo;ve been considering Nemerle, IronRuby and IronPython. I&amp;rsquo;ve also thought of crazy things like Erlang (there is no .net variant, to my knowledge), but that will only be used if there is clear reason for it.&lt;/p&gt;
&lt;p&gt;Two more interesting things. First, I have put up all of my stuff on Subversion, as I cannot wait to get a reliable TFS install anywhere. I did have one, but then the hard drive decided to destroy itself &amp;ndash; I doubt TFS was to blame, but whatever. Being happy with SVN, I also got a &lt;a href="http://nesteruk.fogbugz.com"&gt;free account on FogBugz&lt;/a&gt; so now I track my stuff exclusively there. I must admit that I could just as easily host a JIRA personal license, but since I do commercial stuff, I&amp;rsquo;m really not allowed to. So FogBugz it is.&lt;/p&gt;
&lt;p&gt;More fun in store &amp;ndash; the first meeting of the &lt;a href="http://spbalt.net"&gt;St. Petersburg ALT.NET Group&lt;/a&gt; is probably not that far away, so I&amp;rsquo;m excited to see how things pan out &amp;ndash; assuming the meeting happens at all. It&amp;rsquo;s nice to realize that the developer community hasn&amp;rsquo;t died off due to an economic crisis or something &amp;ndash; though at times it seems that way.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s all for now. I better get back to coding useful programs, lest I lose my .net touch.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/nesteruk/~4/bJWVNRlgqMY" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/nesteruk/~3/bJWVNRlgqMY/post.aspx</link>
      <author>dmitrinesteruk.nospam@nospam.gmail.com (dmitri)</author>
      <comments>http://nesteruk.org/blog/post/Diversification.aspx#comment</comments>
      <guid isPermaLink="false">http://nesteruk.org/blog/post.aspx?id=03f389ec-43e3-47a8-b2d1-10dd5cd9a3ef</guid>
      <pubDate>Mon, 19 Jan 2009 01:55:00 +0300</pubDate>
      <dc:publisher>dmitri</dc:publisher>
      <pingback:server>http://nesteruk.org/blog/pingback.axd</pingback:server>
      <pingback:target>http://nesteruk.org/blog/post.aspx?id=03f389ec-43e3-47a8-b2d1-10dd5cd9a3ef</pingback:target>
      <slash:comments>1</slash:comments>
      <trackback:ping>http://nesteruk.org/blog/trackback.axd?id=03f389ec-43e3-47a8-b2d1-10dd5cd9a3ef</trackback:ping>
      <wfw:comment>http://nesteruk.org/blog/post/Diversification.aspx#comment</wfw:comment>
      <wfw:commentRss>http://nesteruk.org/blog/syndication.axd?post=03f389ec-43e3-47a8-b2d1-10dd5cd9a3ef</wfw:commentRss>
    <feedburner:origLink>http://nesteruk.org/blog/post.aspx?id=03f389ec-43e3-47a8-b2d1-10dd5cd9a3ef</feedburner:origLink></item>
  </channel>
</rss>
