<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;D08BQH8yeSp7ImA9WxNUFUo.&quot;"><id>tag:blogger.com,1999:blog-7577421612120825312</id><updated>2009-11-07T06:37:31.191Z</updated><title>Functional Fun</title><subtitle type="html">Samuel Jack's Adventures in software creation</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://blog.functionalfun.net/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://blog.functionalfun.net/" /><link rel="hub" href="http://pubsubhubbub.appspot.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>Sam</name><uri>http://www.blogger.com/profile/01345100698738870730</uri><email>noreply@blogger.com</email></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>133</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><link rel="license" type="text/html" href="http://creativecommons.org/licenses/by-sa/2.0/" /><link rel="self" href="http://feeds.feedburner.com/FunctionalFun" type="application/atom+xml" /><feedburner:emailServiceId>FunctionalFun</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><entry gd:etag="W/&quot;DkADR3Y9eyp7ImA9WxNUEUU.&quot;"><id>tag:blogger.com,1999:blog-7577421612120825312.post-7663435939183689092</id><published>2009-11-02T17:59:00.001Z</published><updated>2009-11-02T17:59:36.863Z</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-11-02T17:59:36.863Z</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Software" /><category scheme="http://www.blogger.com/atom/ns#" term=".Net" /><category scheme="http://www.blogger.com/atom/ns#" term="WCF" /><title>A Fiddler plug-in for inspecting WCF Binary encoded messages</title><content type="html">&lt;p&gt;If ever you're needing to debug the interaction between a Web Service and its clients, Microsoft’s &lt;a href="http://www.fiddler2.com/fiddler2/" target="_blank"&gt;Fiddler&lt;/a&gt; is the tool to use - this includes WCF Services so long as they're using a HTTP transport. The only thing Fiddler won't do is decode messages that are sent using WCF's proprietary &lt;a href="http://blogs.msdn.com/drnick/archive/2009/09/22/binary-encoding-part-4.aspx" target="_blank"&gt;Binary encoding&lt;/a&gt; - until today, that is: at lunch time, I took advantage of Fiddler's neat extensibility mechanism and created a rough-and-ready Inspector that will translate binary messages from gobbledegook to plain xml for your debugging pleasure. &lt;/p&gt;  &lt;p&gt;You can download the plug-in and source from &lt;a href="http://code.msdn.microsoft.com/wcfbinaryinspector" target="_blank"&gt;MSDN Code Gallery&lt;/a&gt;. To use it, just drop the plug-in&amp;#160; in the Inspectors folder of your Fiddler installation. Once you've reloaded Fiddler, switch to the Inspectors tab and look for WCF Binary.&lt;a href="http://lh3.ggpht.com/_Blokl_3SWiA/Su8eA9v4D_I/AAAAAAAAAko/vI0O6XVYdHQ/s1600-h/WCFBinaryFiddlerPlugin%5B9%5D.png"&gt;&lt;img style="margin: 10px auto 0px; display: block; float: none" title="WCFBinaryFiddlerPlugin" alt="WCFBinaryFiddlerPlugin" src="http://lh5.ggpht.com/_Blokl_3SWiA/Su8eBxIWGNI/AAAAAAAAAks/NaBasI3T3uE/WCFBinaryFiddlerPlugin_thumb%5B7%5D.png?imgmax=800" width="602" height="364" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;h4&gt;&lt;/h4&gt;  &lt;h4&gt;Implementation Notes&lt;/h4&gt;  &lt;ul&gt;   &lt;li&gt;There’s a very helpful page on the Fiddler site which tells you how to &lt;a href="http://www.fiddler2.com/fiddler/dev/Inspectors.asp" target="_blank"&gt;build Inspectors in .Net&lt;/a&gt;. &lt;/li&gt;    &lt;li&gt;Fiddler gives each Inspector the raw bytes of each message, and it can do with it what it likes. Here’s how I decode a WCF Binary encoded message: &lt;/li&gt; &lt;/ul&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:58634879-d6be-4ee1-af3b-df90f2133b19" class="wlWriterEditableSmartContent"&gt;&lt;pre name="code" class="c#"&gt;using System;
using System.Runtime.Serialization;
using System.ServiceModel.Channels;

...

private static readonly BufferManager _bufferManager = BufferManager.CreateBufferManager(int.MaxValue, int.MaxValue);

...

private string GetWcfBinaryMessageAsText(byte[] encodedMessage)
{
    var bindingElement = new BinaryMessageEncodingBindingElement();
    var factory = bindingElement.CreateMessageEncoderFactory();
    var message = factory.Encoder.ReadMessage(new ArraySegment&amp;lt;byte&amp;gt;(encodedMessage), _bufferManager);
    return message.ToString();
}&lt;/pre&gt;&lt;/div&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7577421612120825312-7663435939183689092?l=blog.functionalfun.net'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/tg8luf75cN3_qL7gl4hbmgOED2M/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/tg8luf75cN3_qL7gl4hbmgOED2M/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/tg8luf75cN3_qL7gl4hbmgOED2M/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/tg8luf75cN3_qL7gl4hbmgOED2M/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=a4X13L0z5W0:vvBDxnWE7Fo:VYtfdMxc7SE"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=a4X13L0z5W0:vvBDxnWE7Fo:VYtfdMxc7SE" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=a4X13L0z5W0:vvBDxnWE7Fo:8U7eRf_NmwQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=8U7eRf_NmwQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=a4X13L0z5W0:vvBDxnWE7Fo:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=a4X13L0z5W0:vvBDxnWE7Fo:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=a4X13L0z5W0:vvBDxnWE7Fo:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=a4X13L0z5W0:vvBDxnWE7Fo:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=a4X13L0z5W0:vvBDxnWE7Fo:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=a4X13L0z5W0:vvBDxnWE7Fo:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=a4X13L0z5W0:vvBDxnWE7Fo:l6gmwiTKsz0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=a4X13L0z5W0:vvBDxnWE7Fo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=a4X13L0z5W0:vvBDxnWE7Fo:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=a4X13L0z5W0:vvBDxnWE7Fo:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FunctionalFun/~4/a4X13L0z5W0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.functionalfun.net/feeds/7663435939183689092/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.functionalfun.net/2009/11/fiddler-plug-in-for-inspecting-wcf.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/7663435939183689092?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/7663435939183689092?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FunctionalFun/~3/a4X13L0z5W0/fiddler-plug-in-for-inspecting-wcf.html" title="A Fiddler plug-in for inspecting WCF Binary encoded messages" /><author><name>Sam</name><uri>http://www.blogger.com/profile/01345100698738870730</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09416134415683403048" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.functionalfun.net/2009/11/fiddler-plug-in-for-inspecting-wcf.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0UEQX4zeSp7ImA9WxNVEUQ.&quot;"><id>tag:blogger.com,1999:blog-7577421612120825312.post-5303333033733622762</id><published>2009-10-22T07:00:00.000+01:00</published><updated>2009-10-22T07:00:00.081+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-10-22T07:00:00.081+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Software" /><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><category scheme="http://www.blogger.com/atom/ns#" term="LINQ" /><category scheme="http://www.blogger.com/atom/ns#" term=".Net" /><title>Getting the MethodInfo of a generic method using Lambda expressions</title><content type="html">&lt;p&gt;Getting hold of the &lt;a href="http://msdn.microsoft.com/en-us/library/system.reflection.methodinfo.aspx" target="_blank"&gt;MethodInfo&lt;/a&gt; of a generic method via Reflection (so you can invoke it dynamically, for example) can be a bit of &lt;a href="http://www.aaron-powell.com/blog/october-2008/reflection-and-generics.aspx"&gt;a pain&lt;/a&gt;. So this afternoon I formulated a pain-killer, &lt;em&gt;SymbolExtensions.GetMethodInfo. &lt;/em&gt;It’s not fussy: it works for non-generic methods&lt;em&gt;&amp;#160;&lt;/em&gt;too. You use it like this:&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:713be85c-2c59-4b3f-8938-58cf64e40fd6" class="wlWriterSmartContent"&gt;   &lt;pre class="c#" name="code"&gt;internal class SymbolExtensionsTests
{
    [Test]
    public void GetMethodInfo_should_return_method_info()
    {
        var methodInfo = SymbolExtensions.GetMethodInfo&amp;lt;TestClass&amp;gt;(c =&amp;gt; c.AMethod());
        methodInfo.Name.ShouldEqual(&amp;quot;AMethod&amp;quot;);
    }

    [Test]
    public void GetMethodInfo_should_return_method_info_for_generic_method()
    {
        var methodInfo = SymbolExtensions.GetMethodInfo&amp;lt;TestClass&amp;gt;(c =&amp;gt; c.AGenericMethod(default(int)));

        methodInfo.Name.ShouldEqual(&amp;quot;AGenericMethod&amp;quot;);
        methodInfo.GetParameters().First().ParameterType.ShouldEqual(typeof(int));
    }

    [Test]
    public void GetMethodInfo_should_return_method_info_for_static_method_on_static_class()
    {
        var methodInfo = SymbolExtensions.GetMethodInfo(() =&amp;gt; StaticTestClass.StaticTestMethod());

        methodInfo.Name.ShouldEqual(&amp;quot;StaticTestMethod&amp;quot;);
        methodInfo.IsStatic.ShouldBeTrue();
    }
}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;The active ingredient, as you can see, is &lt;a href="http://msdn.microsoft.com/en-us/library/bb397951.aspx" target="_blank"&gt;Lambda expressions&lt;/a&gt;:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:f052944b-3da8-4041-93e3-a7588b0987dc" class="wlWriterSmartContent"&gt;
  &lt;pre class="c#" name="code"&gt;using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System;

public static class SymbolExtensions
{
    /// &amp;lt;summary&amp;gt;
    /// Given a lambda expression that calls a method, returns the method info.
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;typeparam name=&amp;quot;T&amp;quot;&amp;gt;&amp;lt;/typeparam&amp;gt;
    /// &amp;lt;param name=&amp;quot;expression&amp;quot;&amp;gt;The expression.&amp;lt;/param&amp;gt;
    /// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;
    public static MethodInfo GetMethodInfo(Expression&amp;lt;Action&amp;gt; expression)
    {
        return GetMethodInfo((LambdaExpression)expression);
    }

    /// &amp;lt;summary&amp;gt;
    /// Given a lambda expression that calls a method, returns the method info.
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;typeparam name=&amp;quot;T&amp;quot;&amp;gt;&amp;lt;/typeparam&amp;gt;
    /// &amp;lt;param name=&amp;quot;expression&amp;quot;&amp;gt;The expression.&amp;lt;/param&amp;gt;
    /// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;
    public static MethodInfo GetMethodInfo&amp;lt;T&amp;gt;(Expression&amp;lt;Action&amp;lt;T&amp;gt;&amp;gt; expression)
    {
        return GetMethodInfo((LambdaExpression)expression);
    }

    /// &amp;lt;summary&amp;gt;
    /// Given a lambda expression that calls a method, returns the method info.
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;typeparam name=&amp;quot;T&amp;quot;&amp;gt;&amp;lt;/typeparam&amp;gt;
    /// &amp;lt;param name=&amp;quot;expression&amp;quot;&amp;gt;The expression.&amp;lt;/param&amp;gt;
    /// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;
    public static MethodInfo GetMethodInfo&amp;lt;T, TResult&amp;gt;(Expression&amp;lt;Func&amp;lt;T, TResult&amp;gt;&amp;gt; expression)
    {
        return GetMethodInfo((LambdaExpression)expression);
    }

    /// &amp;lt;summary&amp;gt;
    /// Given a lambda expression that calls a method, returns the method info.
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;param name=&amp;quot;expression&amp;quot;&amp;gt;The expression.&amp;lt;/param&amp;gt;
    /// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;
    public static MethodInfo GetMethodInfo(LambdaExpression expression)
    {
        MethodCallExpression outermostExpression = expression.Body as MethodCallExpression;

        if (outermostExpression == null)
        {
            throw new ArgumentException(&amp;quot;Invalid Expression. Expression should consist of a Method call only.&amp;quot;);
        }

        return outermostExpression.Method;
    }
}&lt;/pre&gt;
&lt;/div&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7577421612120825312-5303333033733622762?l=blog.functionalfun.net'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/_PpRr3Kzvl9TUsLe7BtEqczuOqY/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/_PpRr3Kzvl9TUsLe7BtEqczuOqY/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/_PpRr3Kzvl9TUsLe7BtEqczuOqY/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/_PpRr3Kzvl9TUsLe7BtEqczuOqY/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=yDSKsvfytfU:S-8Hvqx917g:VYtfdMxc7SE"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=yDSKsvfytfU:S-8Hvqx917g:VYtfdMxc7SE" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=yDSKsvfytfU:S-8Hvqx917g:8U7eRf_NmwQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=8U7eRf_NmwQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=yDSKsvfytfU:S-8Hvqx917g:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=yDSKsvfytfU:S-8Hvqx917g:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=yDSKsvfytfU:S-8Hvqx917g:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=yDSKsvfytfU:S-8Hvqx917g:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=yDSKsvfytfU:S-8Hvqx917g:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=yDSKsvfytfU:S-8Hvqx917g:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=yDSKsvfytfU:S-8Hvqx917g:l6gmwiTKsz0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=yDSKsvfytfU:S-8Hvqx917g:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=yDSKsvfytfU:S-8Hvqx917g:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=yDSKsvfytfU:S-8Hvqx917g:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FunctionalFun/~4/yDSKsvfytfU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.functionalfun.net/feeds/5303333033733622762/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.functionalfun.net/2009/10/getting-methodinfo-of-generic-method.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/5303333033733622762?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/5303333033733622762?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FunctionalFun/~3/yDSKsvfytfU/getting-methodinfo-of-generic-method.html" title="Getting the MethodInfo of a generic method using Lambda expressions" /><author><name>Sam</name><uri>http://www.blogger.com/profile/01345100698738870730</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09416134415683403048" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.functionalfun.net/2009/10/getting-methodinfo-of-generic-method.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEMERXs6eyp7ImA9WxNWFUU.&quot;"><id>tag:blogger.com,1999:blog-7577421612120825312.post-3818310554460908896</id><published>2009-10-15T07:00:00.000+01:00</published><updated>2009-10-15T07:00:04.513+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-10-15T07:00:04.513+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Blogging" /><category scheme="http://www.blogger.com/atom/ns#" term="Humour" /><category scheme="http://www.blogger.com/atom/ns#" term="Personal" /><title>Flattery (almost) works</title><content type="html">&lt;p&gt;I checked my email using my smart-phone the other night, and found this:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;Anonymous has left a new comment on your post&lt;/em&gt; &amp;quot;I'll be speaking at PDC 2008...&amp;quot;:&lt;/p&gt;    &lt;p&gt;Masters thesisI have been through the whole content of this blog which is very informative and knowledgeable stuff, So i would like to visit again.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;How nice. I'm always chuffed when somebody takes the time to leave an appreciative comment on my blog. And this one stoked my ego. At a glance it seemed that Mr (or Ms) Anonymous was likening the quality and content of my work to a Masters thesis; though the wording of the message was a little strange ... perhaps English was not their native language?&lt;/p&gt;  &lt;p&gt;Ever polite, the next time I went to my PC I fired up the browser and found the appropriate page on my blog with the intention of thanking Mr (or Ms) Anonymous for their kind words and inviting them to visit as often as they liked.&lt;/p&gt;  &lt;p&gt;But the browser revealed what my phone's mail client had concealed. The words &amp;quot;Masters Thesis&amp;quot; were underlined in blue - a hyperlink to a site whose page rank I will not promote by repeating the link. Cue sound of hissing steam as ego is rapidly quenched.&lt;/p&gt;  &lt;p&gt;Out of curiosity at the wares being peddled by these flattersome spammers, I followed the link, and found offers of written-to-order essays or Masters Thesis - guaranteed native English, and plagiarism free. The kind-hearted scholars at the site will also undertake to complete assignments and exams for online courses and can guarantee to ace them all - for a small consideration of $2000 plus $300 per exam.&lt;/p&gt;  &lt;p&gt;Needless to say, I put my blog's trash-can button to good use.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7577421612120825312-3818310554460908896?l=blog.functionalfun.net'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/eXuU_zsrzH0EL65nczjK7GPdVhs/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/eXuU_zsrzH0EL65nczjK7GPdVhs/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/eXuU_zsrzH0EL65nczjK7GPdVhs/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/eXuU_zsrzH0EL65nczjK7GPdVhs/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=LHiSu6w3YPs:rDmwTCTTo2c:VYtfdMxc7SE"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=LHiSu6w3YPs:rDmwTCTTo2c:VYtfdMxc7SE" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=LHiSu6w3YPs:rDmwTCTTo2c:8U7eRf_NmwQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=8U7eRf_NmwQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=LHiSu6w3YPs:rDmwTCTTo2c:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=LHiSu6w3YPs:rDmwTCTTo2c:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=LHiSu6w3YPs:rDmwTCTTo2c:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=LHiSu6w3YPs:rDmwTCTTo2c:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=LHiSu6w3YPs:rDmwTCTTo2c:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=LHiSu6w3YPs:rDmwTCTTo2c:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=LHiSu6w3YPs:rDmwTCTTo2c:l6gmwiTKsz0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=LHiSu6w3YPs:rDmwTCTTo2c:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=LHiSu6w3YPs:rDmwTCTTo2c:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=LHiSu6w3YPs:rDmwTCTTo2c:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FunctionalFun/~4/LHiSu6w3YPs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.functionalfun.net/feeds/3818310554460908896/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.functionalfun.net/2009/10/flattery-almost-works.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/3818310554460908896?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/3818310554460908896?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FunctionalFun/~3/LHiSu6w3YPs/flattery-almost-works.html" title="Flattery (almost) works" /><author><name>Sam</name><uri>http://www.blogger.com/profile/01345100698738870730</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09416134415683403048" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://blog.functionalfun.net/2009/10/flattery-almost-works.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0YMRXw8fCp7ImA9WxNWEk0.&quot;"><id>tag:blogger.com,1999:blog-7577421612120825312.post-7311875799583292231</id><published>2009-10-10T18:20:00.001+01:00</published><updated>2009-10-10T21:06:24.274+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-10-10T21:06:24.274+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Functional Programming" /><category scheme="http://www.blogger.com/atom/ns#" term="UIAutomation" /><category scheme="http://www.blogger.com/atom/ns#" term="Software" /><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><category scheme="http://www.blogger.com/atom/ns#" term="LINQ" /><category scheme="http://www.blogger.com/atom/ns#" term=".Net" /><title>Practical LINQ #4: Finding a descendant in a tree</title><content type="html">&lt;p&gt;Trees are everywhere. I don’t mean the green, woody variety. I mean the peculiar ones invented by programmers that have their root somewhere in the clouds and branch downwards. As inevitably as apples fall from trees on the heads of meditating physicists, so coders find themselves writing code to traverse tree structures. &lt;/p&gt;  &lt;p&gt;In an &lt;a href="http://blog.functionalfun.net/2009/06/introduction-to-ui-automation-with.html" target="_blank"&gt;earlier post&lt;/a&gt; we explored the tree created by the &lt;a href="http://en.wikipedia.org/wiki/Microsoft_UI_Automation" target="_blank"&gt;UI Automation API&lt;/a&gt; representing all the widgets on the Windows desktop. One very common tree-traversal operation is finding a particular child several nodes down from a root starting point. I &lt;a href="http://blog.functionalfun.net/2009/06/introduction-to-ui-automation-with.html" target="_blank"&gt;gave the example&lt;/a&gt; of locating the Paint.Net drawing canvas within the main window of the application:&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:a7013ba0-fe00-4c61-a5be-f6f3ab8fab9f" class="wlWriterEditableSmartContent"&gt;&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;// find the Paint.Net drawing Canvas
 var canvas = mainWindow.FindDescendentByIdPath(new[] {
     "appWorkspace",
       "workspacePanel",
         "DocumentView",
           "panel",
             "surfaceBox" });&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;What we have here is an extension method, &lt;em&gt;FindDescendentByIdPath&lt;/em&gt;, that starts from a parent element and works its way down through the tree, at each level picking out the child with the given Automation Id. In my last post, I skipped over my implementation of this method, but it deserves a closer look because of the way it uses Functional techniques and LINQ to traverse the hierarchy. &lt;/p&gt;

&lt;p&gt;So here it is:&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:1bffb080-e5be-4e46-bafd-4bf63840aeeb" class="wlWriterEditableSmartContent"&gt;&lt;pre name="code" class="c#"&gt;public static AutomationElement FindDescendentByIdPath(this AutomationElement element, IEnumerable&amp;lt;string&amp;gt; idPath)
{
    var conditionPath = CreateConditionPathForPropertyValues(AutomationElement.AutomationIdProperty, idPath.Cast&amp;lt;object&amp;gt;());

    return FindDescendentByConditionPath(element, conditionPath);
}

public static IEnumerable&amp;lt;Condition&amp;gt; CreateConditionPathForPropertyValues(AutomationProperty property, IEnumerable&amp;lt;object&amp;gt; values)
{
    var conditions = values.Select(value =&amp;gt; new PropertyCondition(property, value));

    return conditions.Cast&amp;lt;Condition&amp;gt;();
}

public static AutomationElement FindDescendentByConditionPath(this AutomationElement element, IEnumerable&amp;lt;Condition&amp;gt; conditionPath)
{
    if (!conditionPath.Any())
    {
        return element;
    }

    var result = conditionPath.Aggregate(
        element,
        (parentElement, nextCondition) =&amp;gt; parentElement == null
                                              ? null
                                              : parentElement.FindChildByCondition(nextCondition));

    return result;
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;The first thing we do is convert the sequence of Automation Id strings into a sequence of Conditions (actually &lt;a href="http://msdn.microsoft.com/en-us/library/system.windows.automation.propertycondition.aspx" target="_blank"&gt;PropertyConditions&lt;/a&gt;) that the UI Automation API can use to pick out children of parent elements. This is handled for us by the &lt;em&gt;CreateConditionPathForPropertyValues &lt;/em&gt;method in line 8.&lt;/p&gt;

&lt;p&gt;The actual method of interest is &lt;em&gt;FindDescendentByConditionPath, &lt;/em&gt;starting in line 15. Here we put the Enumerable.&lt;a href="http://msdn.microsoft.com/en-us/library/bb548744.aspx" target="_blank"&gt;Aggregate&lt;/a&gt; method to a slightly unconventional use. Considered in the abstract, the Aggregate method takes elements from a sequence one by one and performs an function (of your choice) to combine the element with the previous result; the very first element is combined with a seed value. &lt;/p&gt;

&lt;p&gt;In this case the seed value is the parent element at the top of tree, the sequence of elements is the list of conditions that we use to pick out the child at each level of the tree. And we provide a lambda function that, each time it is called, takes the element it found in the previous iteration, together with the next condition from the list and uses an extension method that I demonstrated in the &lt;a href="http://blog.functionalfun.net/2009/06/introduction-to-ui-automation-with.html" target="_blank"&gt;earlier blog post&lt;/a&gt;, FindChildByCondition, to find the appropriate child.&lt;/p&gt;

&lt;p&gt;I’ve found this method a great help when monkeying around in UI Automation trees. If you think you might, look for it in the the &lt;a href="http://code.msdn.microsoft.com/uiautomation" target="_blank"&gt;source code&lt;/a&gt; from last time.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7577421612120825312-7311875799583292231?l=blog.functionalfun.net'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/ZdWX0BkF5G2fUvlCoiqAocdT2vk/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/ZdWX0BkF5G2fUvlCoiqAocdT2vk/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/ZdWX0BkF5G2fUvlCoiqAocdT2vk/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/ZdWX0BkF5G2fUvlCoiqAocdT2vk/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=0RpGBhWzpCU:sW8CVw_M1CU:VYtfdMxc7SE"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=0RpGBhWzpCU:sW8CVw_M1CU:VYtfdMxc7SE" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=0RpGBhWzpCU:sW8CVw_M1CU:8U7eRf_NmwQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=8U7eRf_NmwQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=0RpGBhWzpCU:sW8CVw_M1CU:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=0RpGBhWzpCU:sW8CVw_M1CU:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=0RpGBhWzpCU:sW8CVw_M1CU:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=0RpGBhWzpCU:sW8CVw_M1CU:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=0RpGBhWzpCU:sW8CVw_M1CU:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=0RpGBhWzpCU:sW8CVw_M1CU:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=0RpGBhWzpCU:sW8CVw_M1CU:l6gmwiTKsz0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=0RpGBhWzpCU:sW8CVw_M1CU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=0RpGBhWzpCU:sW8CVw_M1CU:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=0RpGBhWzpCU:sW8CVw_M1CU:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FunctionalFun/~4/0RpGBhWzpCU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.functionalfun.net/feeds/7311875799583292231/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.functionalfun.net/2009/10/practical-linq-4-finding-descendant-in.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/7311875799583292231?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/7311875799583292231?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FunctionalFun/~3/0RpGBhWzpCU/practical-linq-4-finding-descendant-in.html" title="Practical LINQ #4: Finding a descendant in a tree" /><author><name>Sam</name><uri>http://www.blogger.com/profile/01345100698738870730</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09416134415683403048" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.functionalfun.net/2009/10/practical-linq-4-finding-descendant-in.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUUNR3wycCp7ImA9WxNXFU0.&quot;"><id>tag:blogger.com,1999:blog-7577421612120825312.post-4079384939197422683</id><published>2009-10-02T18:08:00.001+01:00</published><updated>2009-10-02T18:08:16.298+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-10-02T18:08:16.298+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="WPF" /><category scheme="http://www.blogger.com/atom/ns#" term="VSTO" /><category scheme="http://www.blogger.com/atom/ns#" term="Software" /><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><category scheme="http://www.blogger.com/atom/ns#" term=".Net" /><title>Work around for WPF Bug: Drag and Drop does not work when executing a WPF application in a non-default AppDomain</title><content type="html">&lt;p&gt;Today's task was implementing Drag/Drop to move items into folders. My estimate of yesterday was 6 hours to get the job done. That should have been plenty: then I discovered the bug.&lt;/p&gt;  &lt;p&gt;We're creating an Excel Addin using &lt;a href="http://www.add-in-express.com/"&gt;Addin-Express&lt;/a&gt; (which is very like VSTO). All the UI for our add-in is built with WPF (naturally). When Addin Express hosts Add-ins for Excel, it isolates them each in their own App-Domain. Which is why today I came to add myself to the list of people who have reproduced this &lt;a href="https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=422485&amp;amp;wa=wsignin1.0"&gt;issue&lt;/a&gt; on the Connect website: &amp;quot;Drag and Drop does not work when executing a WPF application in a non-default AppDomain&amp;quot;&lt;/p&gt;  &lt;p&gt;Googling around the problem, I found that Tao Wen had also encountered the problem, and had managed to &lt;a href="http://www.add-in-express.com/forum/read.php?FID=5&amp;amp;TID=2436"&gt;find something of a work-around&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Having Reflectored around the WPF source-code a little, I can see that when WPF is hosted in a non-default App Domain, the check that the HwndSource class (which manages the Win32 Window object on behalf of the WPF Window class) does to ensure the code has the UnmanagedCode permission fails, so Windows do not register themselves as OLE Drop Targets (see the last few lines of the HwndSource.Initialize method)&lt;/p&gt;  &lt;p&gt;Tao Wen's solution is to use reflection to directly call the internal DragDrop.RegisterDropTarget method. What his solution doesn't take into account is that, when the Window is closed it must unregister itself as a drop target.&lt;/p&gt;  &lt;p&gt;Fortunately, by incrementing the _registeredDropTargetCount field in the HwndSource class we can ensure that HwndSource will itself call DropDrop.RevokeDropTarget when it's disposed (see about half-way down the HwndSource.Dispose method).&lt;/p&gt;  &lt;p&gt;For anybody else who is blocked by the same issue, I've created a little class that will implement the hack on a Window class. Be warned: it uses evil reflection code to access private members of WPF classes, and it might break at any time. Use it at your own risk.&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:06b3b28d-d77e-4ab9-83e2-735de618ba74" class="wlWriterEditableSmartContent"&gt;&lt;pre name="code" class="c#"&gt;/// &amp;lt;summary&amp;gt;
/// Contains a helper method to enable a window as a drop target.
/// &amp;lt;/summary&amp;gt;
public static class DropTargetEnabler
{
    /// &amp;lt;summary&amp;gt;
    /// Enables the window as drop target. Should only be used to work around the bug that
    /// occurs when WPF is hosted in a non-default App Domain
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;param name="window"&amp;gt;The window to enable.&amp;lt;/param&amp;gt;
    /// &amp;lt;remarks&amp;gt;
    /// This is a hack, so should be used with caution. It might stop working in future versions of .Net.
    /// The original wpf bug report is here: http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=422485
    /// &amp;lt;/remarks&amp;gt;
    // This code was inspired by a post made by Tao Wen on the Add-in Express forum:
    // http://www.add-in-express.com/forum/read.php?FID=5&amp;amp;TID=2436
    public static void EnableWindowAsDropTarget(Window window)
    {
        window.Loaded += HandleWindowLoaded;
    }

    private static void HandleWindowLoaded(object sender, RoutedEventArgs e)
    {
        // See the HwndSource.Initialize method to see how it sets up a window as a Drop Target
        // also see the HwndSource.Dispose for how the window is removed as a drop target
        var window = sender as Window;

        IntPtr windowHandle = new WindowInteropHelper(window).Handle;

        // invoking RegisterDropTarget calls Ole32 RegisterDragDrop
        InvokeRegisterDropTarget(windowHandle);

        // to make sure RevokeDragDrop gets called we have to increment the private field
        // _registeredDropTargetCount on the HwndSource instance that the Window is attached to
        EnsureRevokeDropTargetGetsCalled(windowHandle);
    }

    private static void InvokeRegisterDropTarget(IntPtr windowHandle)
    {
        var registerDropTargetMethod = typeof(System.Windows.DragDrop)
            .GetMethod("RegisterDropTarget", BindingFlags.Static | BindingFlags.NonPublic);
        if (registerDropTargetMethod == null)
        {
            throw new InvalidOperationException("The EnableWindowAsDropTarget Hack no longer works!");
        }

        registerDropTargetMethod
            .Invoke(null, new object[] { windowHandle });
    }

    private static void EnsureRevokeDropTargetGetsCalled(IntPtr windowHandle)
    {
        var hwndSource = HwndSource.FromHwnd(windowHandle);
        var fieldInfo = typeof(HwndSource).GetField("_registeredDropTargetCount", BindingFlags.NonPublic | BindingFlags.Instance);
        if (fieldInfo == null)
        {
            throw new InvalidOperationException("The EnableWindowAsDropTarget hack no longer works!");
        }

        var currentValue = (int) fieldInfo.GetValue(hwndSource);
        fieldInfo.SetValue(hwndSource, currentValue + 1);
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Use it like this:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:7ccccdc1-19eb-4361-846e-9c342f5b3461" class="wlWriterEditableSmartContent"&gt;&lt;pre name="code" class="c#"&gt;public partial class MyWindow
 {
        public MyWindow()
        {
            InitializeComponent();
            DropTargetEnabler.EnableWindowAsDropTarget(this);
        }
}
&lt;/pre&gt;&lt;/div&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7577421612120825312-4079384939197422683?l=blog.functionalfun.net'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/6tp2lkD3urpDpWl_s4vurniPLJ4/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/6tp2lkD3urpDpWl_s4vurniPLJ4/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/6tp2lkD3urpDpWl_s4vurniPLJ4/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/6tp2lkD3urpDpWl_s4vurniPLJ4/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=fS6v_XmoPD4:S2PtukJkOjI:VYtfdMxc7SE"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=fS6v_XmoPD4:S2PtukJkOjI:VYtfdMxc7SE" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=fS6v_XmoPD4:S2PtukJkOjI:8U7eRf_NmwQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=8U7eRf_NmwQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=fS6v_XmoPD4:S2PtukJkOjI:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=fS6v_XmoPD4:S2PtukJkOjI:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=fS6v_XmoPD4:S2PtukJkOjI:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=fS6v_XmoPD4:S2PtukJkOjI:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=fS6v_XmoPD4:S2PtukJkOjI:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=fS6v_XmoPD4:S2PtukJkOjI:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=fS6v_XmoPD4:S2PtukJkOjI:l6gmwiTKsz0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=fS6v_XmoPD4:S2PtukJkOjI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=fS6v_XmoPD4:S2PtukJkOjI:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=fS6v_XmoPD4:S2PtukJkOjI:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FunctionalFun/~4/fS6v_XmoPD4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.functionalfun.net/feeds/4079384939197422683/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.functionalfun.net/2009/10/work-around-for-wpf-bug-drag-and-drop.html#comment-form" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/4079384939197422683?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/4079384939197422683?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FunctionalFun/~3/fS6v_XmoPD4/work-around-for-wpf-bug-drag-and-drop.html" title="Work around for WPF Bug: Drag and Drop does not work when executing a WPF application in a non-default AppDomain" /><author><name>Sam</name><uri>http://www.blogger.com/profile/01345100698738870730</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09416134415683403048" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">3</thr:total><feedburner:origLink>http://blog.functionalfun.net/2009/10/work-around-for-wpf-bug-drag-and-drop.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkMEQHY5eSp7ImA9WxNXEkQ.&quot;"><id>tag:blogger.com,1999:blog-7577421612120825312.post-7139755788226522540</id><published>2009-09-30T07:00:00.000+01:00</published><updated>2009-09-30T07:00:01.821+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-09-30T07:00:01.821+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Humour" /><category scheme="http://www.blogger.com/atom/ns#" term="Personal" /><title>Googling a tribute to my Grandfather</title><content type="html">&lt;p&gt;My Grandpa, Dr R.A.F. Jack, passed away a few months ago, aged 89. It was a comfort at his funeral to see how highly regarded he was in the community and beyond: as well as being the village doctor for close to half-a-century, he was a respected and well-loved elder in our church, and he was known in the medical field for his work with homeopathy.&lt;/p&gt;  &lt;p&gt;Though he pre-dated the internet by many years, when I googled his name, I turned up several references. Admittedly, these results were somewhat drowned out by pages referring to a certain &lt;a href="http://www.raf.mod.uk/" target="_blank"&gt;aviationary body&lt;/a&gt;&amp;#160;&lt;a href="http://en.wikipedia.org/wiki/History_of_the_Royal_Air_Force" target="_blank"&gt;born two years before&lt;/a&gt; him. But once I’d filtered those out, I found a few gems.&lt;/p&gt;  &lt;p&gt;I discovered that Amazon stock his book, &lt;a href="http://www.amazon.co.uk/gp/product/0906584515?ie=UTF8&amp;amp;tag=funcfun-21&amp;amp;linkCode=as2&amp;amp;camp=1634&amp;amp;creative=19450&amp;amp;creativeASIN=0906584515"&gt;Homeopathy in General Practice&lt;/a&gt;, currently number 1,252,945 on their Best Seller list. I found a bibliography of his other &lt;a href="http://www.minimum.com/p7/engine/auth.asp?n=1120" target="_blank"&gt;published works.&lt;/a&gt; Then there was a &lt;a href="http://www.trusthomeopathy.org/export/sites/bha_site/hh_article_bank/conditions_m_to_z/Autumn_2003.5_post_polio_syndrome.pdf" target="_blank"&gt;magazine article&lt;/a&gt; about his work written by an appreciative patient. She records his unorthodox method of checking that she wasn’t suffering from a trapped nerve – putting a sandbag under her knee, and bouncing another on top!&lt;/p&gt;  &lt;p&gt;And finally, in the Letters page of the &lt;a href="http://www.pubmedcentral.nih.gov/pagerender.fcgi?artid=2062252&amp;amp;pageindex=1" target="_blank"&gt;British Medical Journal from June 1955&lt;/a&gt; I found this:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;strong&gt;Redundant Circulars       &lt;br /&gt;&lt;/strong&gt;&lt;em&gt;Dr. R. A. F. JACK (Bromsgrove) writes&lt;/em&gt;: My young family have      &lt;br /&gt;helped me to-deal with the surfeit of advertisements that daily      &lt;br /&gt;swell my morning post. The elder two, who by now have lost      &lt;br /&gt;all interest in opening them, content themselves with collecting      &lt;br /&gt;the stamps and bemoan the fact that so many envelopes these      &lt;br /&gt;days are franked. -They then pass them on to the younger two,      &lt;br /&gt;who, armed with a pair of scissors each, cut out patterns or any      &lt;br /&gt;interesting figures or illustrations that take their fancy. They      &lt;br /&gt;preserve all blotters for me; and all large white envelopes that      &lt;br /&gt;can be ungummed are put aside for subsequent painting practice      &lt;br /&gt;or for conversion into paper darts. The result is that my wife and      &lt;br /&gt;I get an extra quarter of an hour's peace each morning, so that in      &lt;br /&gt;one way or another we all benefit from the unremitting onslaught      &lt;br /&gt;of the various drug houses.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;The eldest of the two stamp collectors mentioned is my Dad, now himself a GP, and semi-retired!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7577421612120825312-7139755788226522540?l=blog.functionalfun.net'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/5WcOlLbg0FO4RKrz22CPF1XJCbU/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/5WcOlLbg0FO4RKrz22CPF1XJCbU/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/5WcOlLbg0FO4RKrz22CPF1XJCbU/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/5WcOlLbg0FO4RKrz22CPF1XJCbU/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=yl_opDilL24:sAH3OHlkb3s:VYtfdMxc7SE"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=yl_opDilL24:sAH3OHlkb3s:VYtfdMxc7SE" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=yl_opDilL24:sAH3OHlkb3s:8U7eRf_NmwQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=8U7eRf_NmwQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=yl_opDilL24:sAH3OHlkb3s:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=yl_opDilL24:sAH3OHlkb3s:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=yl_opDilL24:sAH3OHlkb3s:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=yl_opDilL24:sAH3OHlkb3s:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=yl_opDilL24:sAH3OHlkb3s:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=yl_opDilL24:sAH3OHlkb3s:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=yl_opDilL24:sAH3OHlkb3s:l6gmwiTKsz0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=yl_opDilL24:sAH3OHlkb3s:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=yl_opDilL24:sAH3OHlkb3s:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=yl_opDilL24:sAH3OHlkb3s:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FunctionalFun/~4/yl_opDilL24" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.functionalfun.net/feeds/7139755788226522540/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.functionalfun.net/2009/09/googling-tribute-to-my-grandfather.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/7139755788226522540?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/7139755788226522540?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FunctionalFun/~3/yl_opDilL24/googling-tribute-to-my-grandfather.html" title="Googling a tribute to my Grandfather" /><author><name>Sam</name><uri>http://www.blogger.com/profile/01345100698738870730</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09416134415683403048" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.functionalfun.net/2009/09/googling-tribute-to-my-grandfather.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkcFSHg5eSp7ImA9WxNXEk4.&quot;"><id>tag:blogger.com,1999:blog-7577421612120825312.post-1611659385125653426</id><published>2009-09-25T17:56:00.002+01:00</published><updated>2009-09-29T14:13:39.621+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-09-29T14:13:39.621+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term=".Net" /><category scheme="http://www.blogger.com/atom/ns#" term="WCF" /><title>If your WCF service is unexpectedly receiving a null parameter value, try this…</title><content type="html">&lt;p&gt;An interesting problem ate up an hour and a half of my life yesterday morning. It was all to do with a WCF service.&lt;/p&gt;  &lt;p&gt;The parameter that I was carefully formulating on one end of the wire and passing to my service proxy was not being received by my service at the other end - instead it was getting a null value. It worked the day before - why had it stopped working overnight?&lt;/p&gt;  &lt;p&gt;Intercepting the http traffic with the help of the wonderful &lt;a href="http://www.fiddler2.com/fiddler2/"&gt;Fiddler&lt;/a&gt; (and a useful &lt;a href="http://www.west-wind.com/weblog/posts/596348.aspx"&gt;article about Fiddlering .Net by Rick Strahl&lt;/a&gt;) confirmed that a serialized version of the parameter was indeed being sent down the pipe and was arriving at the server - so why wasn't my service getting it?&lt;/p&gt;  &lt;p&gt;After much head-scratching, I thought of checking the history of our Server project in the Source code repository. That gave me the clue I needed. In the file containing the interface which defines the &lt;a href="http://msdn.microsoft.com/en-us/library/ms733070.aspx"&gt;service's contract&lt;/a&gt;, I noticed that the name of the parameter on the method in question had been changed.&lt;/p&gt;  &lt;p&gt;Now at this point I should explain that, partially inspired by &lt;a href="http://www.netfxharmonics.com/2008/11/Understanding-WCF-Services-in-Silverlight-2"&gt;this article&lt;/a&gt;, we have chosen to eschew the usual route of having Visual Studio create our Service proxies for us. We prefer to share the assembly containing the Service contract interfaces and Data Contract objects between the client and the server projects. This approach works very nicely most of the time. It saves us having to "Update Service Reference" every time we change the shape of the sever side, and it reduces our dependence on the magic that Visual Studio usually works on our behalf.&lt;/p&gt;  &lt;p&gt;Where this approach does get a little bit messy is when you want to have &lt;a href="http://msdn.microsoft.com/en-us/library/ms730059.aspx"&gt;asynchronous versions&lt;/a&gt; of the operations on the client side (Begin[Operation] and End[Operation] methods). Clearly we don't need these on the contract implemented by the Server, so what we end up doing is creating a copy of the Contract named something like IContractClient which contains both the synchronous and also asynchronous versions of the operations.&lt;/p&gt;  &lt;p&gt;Now can you see where this is going?&lt;/p&gt;  &lt;p&gt;The problem turned out to be that the name of the parameter on the client version of the contract was different to that on the server version of the contract. The message on the wire contained the client’s (incorrect) name for the parameter. So presumably, when WCF received the message, it failed to match the parameters with those expected by the method on the server, shrugged its shoulders, and passed in a null value to the method.&lt;/p&gt;  &lt;p&gt;But the story doesn't end there. I found the client version of the contract interface, made what I thought was the necessary correction, and whilst Visual Studio was rebuilding I announced to my colleague that I'd fixed the problem. Only to find, when I tested it, that it was still broken.&lt;/p&gt;  &lt;p&gt;More head-scratching, and Fiddlering: the old parameter name was still being passed through. Huh? Clean and Rebuild to make definitely sure the change had stuck. Still no go.&lt;/p&gt;  &lt;p&gt;And then the final ray of light. On the client side we were using the asynchronous version of the operation, so it was the Begin[Operation] method that I'd corrected. And I'd left the synchronous version untouched.&lt;/p&gt;  &lt;p&gt;Once that was corrected everything started working, and I could finally begin the day's work.&lt;/p&gt;  &lt;p&gt;In conclusion, for all you googlers:&lt;/p&gt;  &lt;p&gt;&lt;em&gt;If your WCF service is receiving null values instead of the parameters you are expecting, check that the parameter names on your methods on the client version of the contract match those on the server version of the contract. And on the client side, be sure to check both the synchronous and asynchronous definitions of your methods.&lt;/em&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7577421612120825312-1611659385125653426?l=blog.functionalfun.net'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/dDQpNaCPyIYC1BKhs4SEQbNlhkc/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/dDQpNaCPyIYC1BKhs4SEQbNlhkc/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/dDQpNaCPyIYC1BKhs4SEQbNlhkc/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/dDQpNaCPyIYC1BKhs4SEQbNlhkc/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=hmH9o6NEhm4:EpaqbO6EEvA:VYtfdMxc7SE"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=hmH9o6NEhm4:EpaqbO6EEvA:VYtfdMxc7SE" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=hmH9o6NEhm4:EpaqbO6EEvA:8U7eRf_NmwQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=8U7eRf_NmwQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=hmH9o6NEhm4:EpaqbO6EEvA:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=hmH9o6NEhm4:EpaqbO6EEvA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=hmH9o6NEhm4:EpaqbO6EEvA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=hmH9o6NEhm4:EpaqbO6EEvA:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=hmH9o6NEhm4:EpaqbO6EEvA:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=hmH9o6NEhm4:EpaqbO6EEvA:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=hmH9o6NEhm4:EpaqbO6EEvA:l6gmwiTKsz0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=hmH9o6NEhm4:EpaqbO6EEvA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=hmH9o6NEhm4:EpaqbO6EEvA:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=hmH9o6NEhm4:EpaqbO6EEvA:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FunctionalFun/~4/hmH9o6NEhm4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.functionalfun.net/feeds/1611659385125653426/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.functionalfun.net/2009/09/if-your-wcf-service-is-unexpectedly.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/1611659385125653426?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/1611659385125653426?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FunctionalFun/~3/hmH9o6NEhm4/if-your-wcf-service-is-unexpectedly.html" title="If your WCF service is unexpectedly receiving a null parameter value, try this…" /><author><name>Sam</name><uri>http://www.blogger.com/profile/01345100698738870730</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09416134415683403048" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.functionalfun.net/2009/09/if-your-wcf-service-is-unexpectedly.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkcEQn05cSp7ImA9WxNSEUU.&quot;"><id>tag:blogger.com,1999:blog-7577421612120825312.post-3246327635751602564</id><published>2009-08-25T07:00:00.000+01:00</published><updated>2009-08-25T07:00:03.329+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-08-25T07:00:03.329+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="VB.Net" /><category scheme="http://www.blogger.com/atom/ns#" term="HymnSheet" /><category scheme="http://www.blogger.com/atom/ns#" term="Software" /><category scheme="http://www.blogger.com/atom/ns#" term="Personal" /><category scheme="http://www.blogger.com/atom/ns#" term=".Net" /><title>Introducing HymnSheet – free, simple song presentation software for Churches and Schools</title><content type="html">&lt;p&gt;Our church jumped into the computer age a few years back. We ditched the Overhead Projector that had served us faithfully for many years, and acquired one of its digital brethren, along with a laptop. Ah, OHPs – those were the days – amazing what they could do with just a few lights, lenses, mirrors, and on a good day, no smoke. Anyway, I volunteered to sort out some software to do what the old OHP did for us – display songs on the screen for the Sunday School scholars to sing.&lt;/p&gt;  &lt;p&gt;Powerpoint was an obvious first candidate, but rejected after a few moments consideration: our Sunday School leader likes to be able to add choruses to the mix at a moments notice: imagine try to insert slides into a Powerpoint presentation on the fly!&lt;/p&gt;  &lt;p&gt;Then I scoured the ‘net for more specialised alternatives – and found plenty.But I noticed two things about all of them: firstly, they cost money; and secondly, all of them did too much – we prefer not to have our attention distracted from worship by snazzy graphics and alpha-blended video, or by nursery notices popping up to inform Mrs Jones that little Johnny needs his nappy changing. &lt;/p&gt;  &lt;p&gt;What self-respecting programmer would not see this state of affairs as a challenge? Surely it would only take a few evenings to bash out something that would work exactly the way we wanted it to?&lt;/p&gt;  &lt;p&gt;So (a few)^10 evenings later I had a little application ready to use. And we’ve been using it successfully for the last four years. Dragging and dropping song titles into a playlist sure beats sorting through a deck of transparencies. &lt;/p&gt;  &lt;p&gt;Ever since I started this blog, I’ve been intending to put the application and source code online in the hope that others will find it useful. Finally I’ve got round to it. It is my birthday gift to you all (28 today – I reckon I’ll start feeling grown up in about two years time!).&lt;/p&gt;  &lt;h4&gt;&lt;/h4&gt;  &lt;h4&gt;What you should know about HymnSheet&lt;/h4&gt;  &lt;p&gt;So here it is, imaginatively named HymnSheet: simple song presentation software, especially suitable for children’s services, and, I imagine, School assemblies and music lessons. It features:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Support for dual monitors (or a laptop and a projector). One monitor displays the control screen, the other the song display &lt;/li&gt;    &lt;li&gt;Drag-and-drop interface for putting songs into your play-list and for reordering them on the fly &lt;/li&gt;    &lt;li&gt;Ability for you to highlight the current line of the song, to assist children learning to read &lt;/li&gt;    &lt;li&gt;Easy to use song editor for adding your own songs to the song library &lt;/li&gt;    &lt;li&gt;Whole song displayed at once on screen, with key shortcuts for scrolling between verses and the chorus of the song. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_Blokl_3SWiA/SpL4pGXzZhI/AAAAAAAAAgA/qAETrHAkWKM/s1600-h/DualMonitorSupport%5B4%5D.png"&gt;&lt;img style="margin: 10px auto; display: block; float: none" title="DualMonitorSupport" alt="DualMonitorSupport" src="http://lh5.ggpht.com/_Blokl_3SWiA/SpL4qLCi6dI/AAAAAAAAAgE/KeS2Db_m468/DualMonitorSupport_thumb%5B2%5D.png?imgmax=800" width="643" height="270" /&gt;&lt;/a&gt;Get started by &lt;a href="http://code.msdn.microsoft.com/Release/ProjectReleases.aspx?ProjectName=hymnsheet" target="_blank"&gt;downloading&lt;/a&gt; the installer (note that you’ll need the &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=AB99342F-5D1A-413D-8319-81DA479AB0D7&amp;amp;displaylang=en" target="_blank"&gt;.Net Framework&lt;/a&gt; installed on your computer) and reading the &lt;a href="http://code.msdn.microsoft.com/Release/ProjectReleases.aspx?ProjectName=hymnsheet" target="_blank"&gt;user guide&lt;/a&gt;. I’ve also made available some &lt;a href="http://code.msdn.microsoft.com/Release/ProjectReleases.aspx?ProjectName=hymnsheet" target="_blank"&gt;sample hymns and choruses&lt;/a&gt; (mostly of the more traditional kind) to get you started.&lt;/p&gt;  &lt;p&gt;If you find this useful, you might like to help me persuade my wife that it was worth my while - if you’re sufficiently persuasive, she may allow me the time to add some new features:&lt;a title="PayPal - The safer, easier way to pay online." href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&amp;amp;hosted_button_id=7724313" target="_blank"&gt;&lt;img style="margin: 5px auto 0px; display: block; float: none" src="https://www.paypal.com/en_GB/i/btn/btn_donate_SM.gif" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;h4&gt;Points of interest in the Source Code&lt;/h4&gt;  &lt;p&gt;For the more technically minded, I’ve made the &lt;a href="http://code.msdn.microsoft.com/Release/ProjectReleases.aspx?ProjectName=hymnsheet" target="_blank"&gt;source code to HymnSheet&lt;/a&gt; available – feel free to adapt it and add to it if you want – I’d love to hear from you if you do. Some points of interest in the source code :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;The code is written in VB.Net.&amp;#160; I know, I’m sorry. Reason is, I started working on this in the days before I had broadband. At the time I only had a CD of Visual Basic 2005 Express Beta which I’d picked up at a conference. By the time I had a a &lt;em&gt;proper&lt;/em&gt; language installed on my machine, I didn’t fancy the job of rewriting ;-). Maybe one day… &lt;/li&gt;    &lt;li&gt;Songs are stored in xml format. I use an &lt;a href="http://msdn.microsoft.com/en-us/library/system.xml.xsl.xsltransform.aspx" target="_blank"&gt;XSL transform&lt;/a&gt; to turn this into HTML (with CSS to style it) and then display it in a &lt;a href="http://msdn.microsoft.com/en-us/library/system.windows.forms.webbrowser.aspx" target="_blank"&gt;Webbrowser control&lt;/a&gt; (maximised to fill the whole of the display screen). This gives you complete control over the way songs are presented. In particular, you might want to change the fonts or colours – the settings for these are in the &lt;em&gt;songs.css&lt;/em&gt; file. &lt;/li&gt;    &lt;li&gt;If you’ve never taken a look at the &lt;a href="http://msdn.microsoft.com/en-us/library/system.windows.forms.webbrowser.aspx" target="_blank"&gt;Webbrowser control&lt;/a&gt;, you should – it’s cool. As well as letting you load HTML from memory, it provides a managed DOM view of the HTML document, complete with events; you can also invoke any scripts embedded in the page. &lt;/li&gt;    &lt;li&gt;I use some Javascript to animate the movement between verses. From IE 7 onwards, the default security settings prevent javascript from running in a HTML document that is loaded from memory (as is the case in HymnSheet). If you host the Webbrowser control in an application and want to enable javascript, you need to set a &lt;a href="http://msdn.microsoft.com/en-us/library/ms649488(VS.85).aspx" target="_blank"&gt;key in the registry&lt;/a&gt;: &lt;em&gt;[HKEY_LOCAL_MACHINE or HKEY_CURRENT_USER]\SOFTWARE\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BLOCK_LMZ_SCRIPT\[You executable name.exe],&lt;/em&gt; with value of 0. I do this in the installer, but I’ve also created a class with a method that will enable scripting for the current application: look for it in the source code – it’s called EnableWebBrowserScripting. &lt;/li&gt;    &lt;li&gt;I’ve included the source code for the installer (see &lt;em&gt;HymnSheet.wxs&lt;/em&gt;). If you want to build this, you’ll need to install &lt;a href="http://wix.sourceforge.net/" target="_blank"&gt;WiX&lt;/a&gt;, the Windows Installer XML toolkit; you might also want to try out the excellent &lt;a href="http://wixedit.sourceforge.net/" target="_blank"&gt;WixEdit&lt;/a&gt; for editing Wix scripts. &lt;/li&gt; &lt;/ul&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7577421612120825312-3246327635751602564?l=blog.functionalfun.net'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/eykIw8W2zwkoGyJtetCDyC5Ty-k/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/eykIw8W2zwkoGyJtetCDyC5Ty-k/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/eykIw8W2zwkoGyJtetCDyC5Ty-k/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/eykIw8W2zwkoGyJtetCDyC5Ty-k/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=NZkzkeMaitQ:KmYs85Cir-4:VYtfdMxc7SE"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=NZkzkeMaitQ:KmYs85Cir-4:VYtfdMxc7SE" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=NZkzkeMaitQ:KmYs85Cir-4:8U7eRf_NmwQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=8U7eRf_NmwQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=NZkzkeMaitQ:KmYs85Cir-4:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=NZkzkeMaitQ:KmYs85Cir-4:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=NZkzkeMaitQ:KmYs85Cir-4:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=NZkzkeMaitQ:KmYs85Cir-4:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=NZkzkeMaitQ:KmYs85Cir-4:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=NZkzkeMaitQ:KmYs85Cir-4:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=NZkzkeMaitQ:KmYs85Cir-4:l6gmwiTKsz0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=NZkzkeMaitQ:KmYs85Cir-4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=NZkzkeMaitQ:KmYs85Cir-4:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=NZkzkeMaitQ:KmYs85Cir-4:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FunctionalFun/~4/NZkzkeMaitQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.functionalfun.net/feeds/3246327635751602564/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.functionalfun.net/2009/08/introducing-hymnsheet-free-simple-song.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/3246327635751602564?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/3246327635751602564?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FunctionalFun/~3/NZkzkeMaitQ/introducing-hymnsheet-free-simple-song.html" title="Introducing HymnSheet – free, simple song presentation software for Churches and Schools" /><author><name>Sam</name><uri>http://www.blogger.com/profile/01345100698738870730</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09416134415683403048" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://blog.functionalfun.net/2009/08/introducing-hymnsheet-free-simple-song.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEcER3c7fSp7ImA9WxNTEUs.&quot;"><id>tag:blogger.com,1999:blog-7577421612120825312.post-8853848008336117353</id><published>2009-08-04T21:49:00.001+01:00</published><updated>2009-08-13T13:20:06.905+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-08-13T13:20:06.905+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="UIAutomation" /><category scheme="http://www.blogger.com/atom/ns#" term="Software" /><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><category scheme="http://www.blogger.com/atom/ns#" term=".Net" /><category scheme="http://www.blogger.com/atom/ns#" term="How to" /><title>An introduction to UI Automation – with spooky spirographs</title><content type="html">&lt;p&gt;A few weeks ago, I unearthed a hidden gem in the .Net framework: the UIAutomation API. UI Automation made its entrance as part of .Net 3.0, but was overshadowed by the trio of W*Fs – if they’d named it Windows Automation Foundation it might have received more love! UIAutomation provides a robust way of poking, prodding and perusing any widget shown on the Windows desktop; it even works with &lt;a href="http://www.silverlightshow.net/items/Accessibility-and-UI-Automation-in-Silverlight-2.aspx"&gt;Silverlight&lt;/a&gt;. It can be used for many things, like building Screen Readers, writing automated UI tests – or for creating a digital spirit to spook your colleagues by possessing &lt;a href="http://www.getpaint.net/" target="_blank"&gt;Paint.Net&lt;/a&gt; and sketching &lt;a href="http://en.wikipedia.org/wiki/Spirograph" target="_blank"&gt;spirographs&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_Blokl_3SWiA/SniEzySYfRI/AAAAAAAAAfY/lxnIeSUtReA/s1600-h/Spirograph%5B4%5D.png"&gt;&lt;img style="display: block; float: none; margin-left: auto; margin-right: auto" title="Spirograph in Paint.Net" alt="Spirograph in Paint.Net" src="http://lh3.ggpht.com/_Blokl_3SWiA/SniE04azCdI/AAAAAAAAAfc/b5xLQn8HEbM/Spirograph_thumb%5B2%5D.png?imgmax=800" width="505" height="362" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;The UI Automation framework reduces the entire contents of the Windows Desktop to a tree of AutomationElement objects. Every widget of any significance, from Windows, to Menu Items, to Text Boxes is represented in the tree. The root of this tree is the Desktop window. You get hold of it, logically enough, using the static &lt;a href="http://msdn.microsoft.com/en-us/library/system.windows.automation.automationelement.rootelement.aspx" target="_blank"&gt;AutomationElement.RootElement&lt;/a&gt; property. From there you can traverse your way down the tree to just about any element on screen using two suggestively named methods on AutomationElement, FindAll and FindFirst.&lt;/p&gt;  &lt;p&gt;Each of these two methods takes a &lt;a href="http://msdn.microsoft.com/en-us/library/system.windows.automation.automationelement.rootelement.aspx" target="_blank"&gt;&lt;em&gt;Condition&lt;/em&gt;&lt;/a&gt; instance as a parameter, and it uses this to pick out the elements you’re looking for. The most useful kind of condition is a &lt;a href="http://msdn.microsoft.com/en-us/library/system.windows.automation.propertycondition.aspx" target="_blank"&gt;&lt;em&gt;PropertyCondition&lt;/em&gt;&lt;/a&gt;. AutomationElements each have a number of properties like Name, Class, AutomationId, ProcessId, etc, exposing their intimate details to the world; these are what you use in the PropertyCondition to distinguish an element from its siblings when you’re hunting for it using one of the Find methods.&lt;/p&gt;  &lt;h4&gt;&lt;/h4&gt;  &lt;h4&gt;Finding Elements to automate&lt;/h4&gt;  &lt;p&gt;Let me show you an example. We want to automate Paint.Net, so first we fire up an instance of the Paint.Net process:&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:20b38e45-1699-4378-afbd-788d4295d008" class="wlWriterEditableSmartContent"&gt;&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;private string PaintDotNetPath = @"C:\Program Files\Paint.NET\PaintDotNet.exe";

...

var processStartInfo = new ProcessStartInfo(paintDotNetPath);
var process = Process.Start(processStartInfo);
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Having started it up, we wait for it to initialize (the Delay method simply calls Thread.Sleep with the appropriate timespan):&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:10e48fa4-ed53-47de-83d4-21841d8bfbab" class="wlWriterEditableSmartContent"&gt;&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;process.WaitForInputIdle();
Delay(4000);
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;At this point, Paint.Net is up on screen, waiting for us to start doodling. This is where the UIAutomation bit begins. We need to get hold of Paint.Net’s main Window. Since we know the Process Id of Paint.Net, we’ll use a PropertyCondition bound to the ProcessId property:&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:61aab1f3-9d27-4514-9b86-7ce3a0d7d365" class="wlWriterEditableSmartContent"&gt;&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;var mainWindow = AutomationElement.RootElement.FindChildByProcessId(process.Id);
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;You won’t find the FindChildByProcessId method on the AutomationElement class: it’s an extension method I’ve created to wrap the call to FindFirst:&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:f8ad7f22-67ba-4920-acb7-87a52cc77613" class="wlWriterEditableSmartContent"&gt;&lt;pre name="code" class="c#"&gt;public static class AutomationExtensions
{
   public static AutomationElement FindChildByProcessId(this AutomationElement element, int processId)
   {
       var result = element.FindChildByCondition(
           new PropertyCondition(AutomationElement.ProcessIdProperty, processId));

       return result;
   }

   public static AutomationElement FindChildByCondition(this AutomationElement element, Condition condition)
   {
       var result = element.FindFirst(
           TreeScope.Children,
           condition);

       return result;
   }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Having found the main screen, we need to dig into it to find the actual drawing canvas element. This is were we need &lt;a href="http://msdn.microsoft.com/en-us/library/ms727247.aspx"&gt;UISpy&lt;/a&gt; (which comes as part of the Windows SDK). UISpy lays bare the automation tree of the desktop and the applications on it. You can use it to snoop at the properties of any AutomationElement on screen, and to make snooping a snap, it has a particularly helpful mode where you can Ctrl-Click an element on screen to locate the corresponding AutomationElement in the automation tree (click the mouse icon on the UISpy toolbar to activate this mode). Using these special powers it doesn’t take long to discover that the drawing canvas is an element with AutomationId property set to “surfaceBox”, and is a child of another element, with AutomationId set to “panel”, which in turn is a child of another element with [&lt;em&gt;snip - I’ll spare you the details&lt;/em&gt;], which is a child of the Paint.Net main window.&lt;a href="http://lh6.ggpht.com/_Blokl_3SWiA/SniE2Nf1D8I/AAAAAAAAAfg/SxuL5ZMtOgE/s1600-h/UISpy%5B4%5D.png"&gt;&lt;img style="margin: 10px auto 0px; display: block; float: none" title="Spying on Paint.Net with UISpy" alt="Spying on Paint.Net with UISpy" src="http://lh6.ggpht.com/_Blokl_3SWiA/SniE3ebQSnI/AAAAAAAAAfk/NsB5edMVyK8/UISpy_thumb%5B2%5D.png?imgmax=800" width="536" height="393" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To assist in navigating this kind of hierarchy (a task you have to do all the time when automating any non-trivial application), I’ve cooked up the &lt;em&gt;FindDescendentByIdPath &lt;/em&gt;extension method (the implementation of which is a whole other blog post). With that, finding the drawing canvas element is as simple as:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:6700d8f5-44b4-4de9-a12e-f520d8f68f95" class="wlWriterEditableSmartContent"&gt;&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;// find the Paint.Net drawing Canvas
var canvas = mainWindow.FindDescendentByIdPath(new[] {
    "appWorkspace",
      "workspacePanel",
        "DocumentView",
          "panel",
            "surfaceBox" });&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;&lt;/h4&gt;

&lt;h4&gt;Animating the Mouse&lt;/h4&gt;

&lt;p&gt;Now for the fun part. Do you remember &lt;a href="http://en.wikipedia.org/wiki/Spirograph"&gt;Spirographs&lt;/a&gt;? They are mathematical toys for drawing pretty geometrical pictures. But have you ever tried drawing one freehand?  Well here’s your chance to convince your friends that you have artistic talents surpassing &lt;a href="http://www.saburchill.com/history/biblio/009.html"&gt;Michelangelo’s&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Jürgen Köller has very kindly written up the &lt;a href="http://www.mathematische-basteleien.de/spirographs.htm"&gt;mathematical equations&lt;/a&gt; that produce these pretty pictures, and I’ve translated them into a C# iterator that produces a sequence of points along the spirograph curve (don’t worry too much about littleR, bigR, etc. – they’re the parameters that govern the shape of the spirograph):&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:fd8d87b4-f213-4494-a236-2cd19796f49c" class="wlWriterEditableSmartContent"&gt;&lt;pre name="code" class="c#"&gt;private IEnumerable&amp;lt;Point&amp;gt; GetPointsForSpirograph(int centerX, int centerY, double littleR, double bigR, double a, int tStart, int tEnd)
{
   // Equations from http://www.mathematische-basteleien.de/spirographs.htm
   for (double t = tStart; t &amp;lt; tEnd; t+= 0.1)
   {
       var rDifference = bigR - littleR;
       var rRatio = littleR / bigR;
       var x = (rDifference * Math.Cos(rRatio * t) + a * Math.Cos((1 - rRatio) * t)) * 25;
       var y = (rDifference * Math.Sin(rRatio * t) - a * Math.Sin((1 - rRatio) * t)) * 25;

       yield return new Point(centerX + (int)x, centerY + (int)y);
   }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;So where are we? We have the Paint.Net canvas open on screen, and we have a set of points that we want to render. Conveniently for us, the default tool in Paint.Net is the brush tool. So to sketch out the spirograph, we just need to automate the mouse to move over the canvas, press the left button, move from point to point, and release the left button. As far as I know there’s no functionality built into the UIAutomation API to automate the mouse, but the &lt;a href="http://www.codeplex.com/TestApi"&gt;WPF TestAPI&lt;/a&gt; (free to download from &lt;a href="http://testapi.codeplex.com/Release/ProjectReleases.aspx"&gt;CodePlex&lt;/a&gt;) compensates for that. In its static &lt;em&gt;Mouse&lt;/em&gt; class it provides &lt;em&gt;Up&lt;/em&gt;, &lt;em&gt;Down&lt;/em&gt;, and &lt;em&gt;MoveTo&lt;/em&gt; methods that do all we need.&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:e4c2d002-4379-4946-953a-3d2e759ecde7" class="wlWriterEditableSmartContent"&gt;&lt;pre name="code" class="c#"&gt;private void DrawSpirographWaveOnCanvas(AutomationElement canvasElement)
{
   var bounds = canvasElement.Current.BoundingRectangle;

   var centerX = (int)(bounds.X + bounds.Width /2);
   int centerY = (int)(bounds.Y + bounds.Height / 2);

   var points = GetPointsForSpirograph(centerX, centerY, 1.02, 5, 2, 0, 300);

   Mouse.MoveTo(points.First());
   Mouse.Down(MouseButton.Left);

   AnimateMouseThroughPoints(points);

   Mouse.Up(MouseButton.Left);
}

private void AnimateMouseThroughPoints(IEnumerable&amp;lt;Point&amp;gt; points)
{
   foreach (var point in points)
   {
       Mouse.MoveTo(point);
       Delay(5);
   }
}&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;Clicking Buttons&lt;/h4&gt;

&lt;p&gt;Once sufficient time has elapsed for your colleagues to admire the drawing, the last thing our automation script needs to do is tidy away – close down Paint.Net, in other words. This allows me to demonstrate another aspect of UIAutomation – how to manipulate elements on screen other than by simulating mouse moves and clicks. &lt;/p&gt;

&lt;p&gt;Shutting down Paint.Net when there is an unsaved document requires two steps: clicking the Close button, and then clicking “Don’t Save” in the confirmation dialog box. As before, we use UISpy to discover the Automation Id of the Close button and its parents so that we can get a reference to the appropriate AutomationElement:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:4b261bba-704b-4431-bc90-c50d0a66a09f" class="wlWriterEditableSmartContent"&gt;&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;var closeButton = mainWindow.FindDescendentByIdPath(new[] {"TitleBar", "Close"});&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now that we have the button, we can get hold of its &lt;em&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/system.windows.automation.invokepattern.aspx" target="_blank"&gt;Invoke&lt;/a&gt;&lt;/em&gt; pattern. Depending on what kind of widget it represents, every AutomationElement makes available certain &lt;a href="http://msdn.microsoft.com/en-us/library/ms752362.aspx" target="_blank"&gt;Patterns&lt;/a&gt;. These Patterns cover the kinds of interaction that are possible with that widget. So,for example, buttons (and button-like things such as hyperlinks) support the &lt;em&gt;Invoke&lt;/em&gt; pattern with a method for Invoking the action, list items support the &lt;em&gt;SelectionItem&lt;/em&gt; pattern with methods for selecting the item, or adding it to the selection, and Text Boxes support the Text pattern with methods for selecting a range of text and querying its attributes. On MSDN, you’ll find a full list of the &lt;a href="http://msdn.microsoft.com/en-us/library/ms752362.aspx"&gt;available patterns&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To invoke the methods of a pattern on a particular AutomationElement, you need to get hold of a reference to the pattern implementation on the element. First you find the appropriate pattern meta-data. For the Invoke pattern, for example, this would be &lt;em&gt;InvokePattern.Pattern&lt;/em&gt;; other patterns follow the same convention. Then you pass that meta-data to the &lt;em&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/system.windows.automation.automationelement.getcurrentpattern.aspx"&gt;GetCurrentPattern&lt;/a&gt;&lt;/em&gt; method on the AutomationElement class. When you’ve got a reference to the pattern implementation, you can go ahead an invoke the relevant methods.&lt;/p&gt;

&lt;p&gt;Once again, I’ve made all this a bit easier by creating some extension methods (only the InvokePattern is shown here; extension methods for other patterns are available in the sample code):&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:6d4fe53c-ab0f-472c-9e58-bb4da81bd022" class="wlWriterEditableSmartContent"&gt;&lt;pre name="code" class="c#"&gt;public static class PatternExtensions
{
   public static InvokePattern GetInvokePattern(this AutomationElement element)
   {
       return element.GetPattern&amp;lt;InvokePattern&amp;gt;(InvokePattern.Pattern);
   }

   public static T GetPattern&amp;lt;T&amp;gt;(this AutomationElement element, AutomationPattern pattern) where T : class
   {
       var patternObject = element.GetCurrentPattern(pattern);

       return patternObject as T;
   }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;With that I can now click the close button:&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:6e39b1fa-fa3d-4eed-936d-d2af4cff45a2" class="wlWriterEditableSmartContent"&gt;&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;closeButton.GetInvokePattern().Invoke();&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Then, after a short delay to allow the confirmation dialog to show up, I can click the &lt;em&gt;Don’t Save&lt;/em&gt; button:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:011adce5-7534-45c8-8752-08e9b82bb767" class="wlWriterEditableSmartContent"&gt;&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;// give chance for the close dialog to show
Delay();

var dontSaveButton = mainWindow.FindDescendentByNamePath(new[] {"Unsaved Changes", "Don't Save"});

Mouse.MoveTo(dontSaveButton.GetClickablePoint().ToDrawingPoint());
Mouse.Click(MouseButton.Left);&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;For variation, I click this button by actually moving the mouse to its centre (line 6) then performing the click.&lt;/p&gt;

&lt;p&gt;All the code is available on &lt;a href="http://code.msdn.microsoft.com/uiautomation" target="_blank"&gt;MSDN Code Gallery&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;&lt;/h4&gt;

&lt;h4&gt;Bowing out&lt;/h4&gt;

&lt;p&gt;When I first read about UI Automation, I got the impression that it was rather complicated, with lots of code needed to make it do anything useful. I tried using &lt;a href="http://www.codeplex.com/white"&gt;Project White&lt;/a&gt; (a &lt;a href="http://opensource.thoughtworks.com/"&gt;Thoughtworks&lt;/a&gt; sponsored wrapper around UIAutomation), thinking that would save me from the devilish details. It turned out the Project White introduced complexities of its own, and actually, UI Automation is pretty straightforward to use, especially when oiled with my extension methods. I’ve had a lot of fun using it to create automated tests of our product over the last couple of months.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7577421612120825312-8853848008336117353?l=blog.functionalfun.net'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/ehgXjgtY_rkUYf4t-xOElEnkD9Y/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/ehgXjgtY_rkUYf4t-xOElEnkD9Y/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/ehgXjgtY_rkUYf4t-xOElEnkD9Y/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/ehgXjgtY_rkUYf4t-xOElEnkD9Y/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=CvEgGj9llOQ:G5BmD4gA7x8:VYtfdMxc7SE"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=CvEgGj9llOQ:G5BmD4gA7x8:VYtfdMxc7SE" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=CvEgGj9llOQ:G5BmD4gA7x8:8U7eRf_NmwQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=8U7eRf_NmwQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=CvEgGj9llOQ:G5BmD4gA7x8:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=CvEgGj9llOQ:G5BmD4gA7x8:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=CvEgGj9llOQ:G5BmD4gA7x8:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=CvEgGj9llOQ:G5BmD4gA7x8:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=CvEgGj9llOQ:G5BmD4gA7x8:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=CvEgGj9llOQ:G5BmD4gA7x8:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=CvEgGj9llOQ:G5BmD4gA7x8:l6gmwiTKsz0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=CvEgGj9llOQ:G5BmD4gA7x8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=CvEgGj9llOQ:G5BmD4gA7x8:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=CvEgGj9llOQ:G5BmD4gA7x8:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FunctionalFun/~4/CvEgGj9llOQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.functionalfun.net/feeds/8853848008336117353/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.functionalfun.net/2009/06/introduction-to-ui-automation-with.html#comment-form" title="9 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/8853848008336117353?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/8853848008336117353?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FunctionalFun/~3/CvEgGj9llOQ/introduction-to-ui-automation-with.html" title="An introduction to UI Automation – with spooky spirographs" /><author><name>Sam</name><uri>http://www.blogger.com/profile/01345100698738870730</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09416134415683403048" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">9</thr:total><feedburner:origLink>http://blog.functionalfun.net/2009/06/introduction-to-ui-automation-with.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkEHQnY7eip7ImA9WxJUF0k.&quot;"><id>tag:blogger.com,1999:blog-7577421612120825312.post-2988700977490094436</id><published>2009-07-16T13:50:00.001+01:00</published><updated>2009-07-16T13:50:33.802+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-07-16T13:50:33.802+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Humour" /><title>How wide?</title><content type="html">&lt;p&gt;A flier came through our door this morning from a new dental practice in the town. Next to a mug shot of two grinning models with impossibly white teeth, it itemises the services provided by the dentists:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Zoom tooth whitening &lt;/li&gt;    &lt;li&gt;Air Flow Stain Removal &lt;/li&gt;    &lt;li&gt;Gum Disease Treatment &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;then&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Wheelchair Access &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;That would make me think twice when the dentist says “Open wide”.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7577421612120825312-2988700977490094436?l=blog.functionalfun.net'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/IKnsIk4EFNQ_R7N0TsmY1d0IlqI/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/IKnsIk4EFNQ_R7N0TsmY1d0IlqI/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/IKnsIk4EFNQ_R7N0TsmY1d0IlqI/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/IKnsIk4EFNQ_R7N0TsmY1d0IlqI/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=1DVEZdavZik:XFLABscXCxQ:VYtfdMxc7SE"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=1DVEZdavZik:XFLABscXCxQ:VYtfdMxc7SE" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=1DVEZdavZik:XFLABscXCxQ:8U7eRf_NmwQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=8U7eRf_NmwQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=1DVEZdavZik:XFLABscXCxQ:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=1DVEZdavZik:XFLABscXCxQ:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=1DVEZdavZik:XFLABscXCxQ:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=1DVEZdavZik:XFLABscXCxQ:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=1DVEZdavZik:XFLABscXCxQ:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=1DVEZdavZik:XFLABscXCxQ:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=1DVEZdavZik:XFLABscXCxQ:l6gmwiTKsz0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=1DVEZdavZik:XFLABscXCxQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=1DVEZdavZik:XFLABscXCxQ:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=1DVEZdavZik:XFLABscXCxQ:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FunctionalFun/~4/1DVEZdavZik" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.functionalfun.net/feeds/2988700977490094436/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.functionalfun.net/2009/07/how-wide.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/2988700977490094436?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/2988700977490094436?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FunctionalFun/~3/1DVEZdavZik/how-wide.html" title="How wide?" /><author><name>Sam</name><uri>http://www.blogger.com/profile/01345100698738870730</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09416134415683403048" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.functionalfun.net/2009/07/how-wide.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUYAQXYyfSp7ImA9WxJVE00.&quot;"><id>tag:blogger.com,1999:blog-7577421612120825312.post-3446099853579273581</id><published>2009-06-29T21:25:00.001+01:00</published><updated>2009-06-29T21:25:40.895+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-29T21:25:40.895+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Personal" /><title>Shipped!</title><content type="html">&lt;p&gt;I’m pleased to announce that acceptance testing has been completed, and &lt;a href="http://blog.functionalfun.net/2008/12/announcing-new-family-development.html"&gt;Baby Jack 2.0&lt;/a&gt;, now officially named &lt;strong&gt;Alaric Nahum Jack, &lt;/strong&gt;was successfully delivered late last week.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_Blokl_3SWiA/SkkjQQiK7cI/AAAAAAAAAdA/PbzANaGK2Pk/s1600-h/P1040594%5B6%5D.jpg"&gt;&lt;img title="P1040594" style="display: block; float: none; margin-left: auto; margin-right: auto" height="384" alt="P1040594" src="http://lh3.ggpht.com/_Blokl_3SWiA/SkkjROpl9wI/AAAAAAAAAdE/XCDnDkLs0hQ/P1040594_thumb%5B4%5D.jpg?imgmax=800" width="501" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;The last few hours of the shipping process were rather gruelling for certain members of the team – my wife was allowed to bliss out on Gas and Air (known to the trade as &lt;a href="http://en.wikipedia.org/wiki/Entonox"&gt;Entonox&lt;/a&gt;), but I was not permitted ear plugs!&lt;/p&gt;  &lt;p&gt;Unfortunately, no documentation was provided, but I do have two weeks off work to try to figure out how he works!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7577421612120825312-3446099853579273581?l=blog.functionalfun.net'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/ijj2JDYnR770wQUnzKqZuadfxMQ/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/ijj2JDYnR770wQUnzKqZuadfxMQ/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/ijj2JDYnR770wQUnzKqZuadfxMQ/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/ijj2JDYnR770wQUnzKqZuadfxMQ/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=imwPTYgbXj0:VCaRZwI9hTU:VYtfdMxc7SE"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=imwPTYgbXj0:VCaRZwI9hTU:VYtfdMxc7SE" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=imwPTYgbXj0:VCaRZwI9hTU:8U7eRf_NmwQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=8U7eRf_NmwQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=imwPTYgbXj0:VCaRZwI9hTU:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=imwPTYgbXj0:VCaRZwI9hTU:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=imwPTYgbXj0:VCaRZwI9hTU:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=imwPTYgbXj0:VCaRZwI9hTU:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=imwPTYgbXj0:VCaRZwI9hTU:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=imwPTYgbXj0:VCaRZwI9hTU:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=imwPTYgbXj0:VCaRZwI9hTU:l6gmwiTKsz0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=imwPTYgbXj0:VCaRZwI9hTU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=imwPTYgbXj0:VCaRZwI9hTU:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=imwPTYgbXj0:VCaRZwI9hTU:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FunctionalFun/~4/imwPTYgbXj0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.functionalfun.net/feeds/3446099853579273581/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.functionalfun.net/2009/06/shipped.html#comment-form" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/3446099853579273581?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/3446099853579273581?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FunctionalFun/~3/imwPTYgbXj0/shipped.html" title="Shipped!" /><author><name>Sam</name><uri>http://www.blogger.com/profile/01345100698738870730</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09416134415683403048" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">4</thr:total><feedburner:origLink>http://blog.functionalfun.net/2009/06/shipped.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkYEQXg6eyp7ImA9WxJWE0w.&quot;"><id>tag:blogger.com,1999:blog-7577421612120825312.post-367052749553595012</id><published>2009-06-17T12:33:00.001+01:00</published><updated>2009-06-18T09:35:00.613+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-18T09:35:00.613+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Humour" /><title>Magnetic Personalities</title><content type="html">&lt;p&gt;A friend of ours happened to be listening in as a primary school teacher was giving a lesson on Electricity and Magnetism.&lt;/p&gt;  &lt;p&gt;“What &lt;em&gt;M&lt;/em&gt; picks things up?” the teacher asked the children. Then, choosing a child from the bunch waving their hands in the air, “Yes?”&lt;/p&gt;  &lt;p&gt;“Mum!” replied the astute scholar of human nature.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7577421612120825312-367052749553595012?l=blog.functionalfun.net'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/KEvxfwuB23yhVTkbou2kF7JlxGQ/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/KEvxfwuB23yhVTkbou2kF7JlxGQ/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/KEvxfwuB23yhVTkbou2kF7JlxGQ/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/KEvxfwuB23yhVTkbou2kF7JlxGQ/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=NyFYG_28tbw:QAUImi0taZU:VYtfdMxc7SE"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=NyFYG_28tbw:QAUImi0taZU:VYtfdMxc7SE" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=NyFYG_28tbw:QAUImi0taZU:8U7eRf_NmwQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=8U7eRf_NmwQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=NyFYG_28tbw:QAUImi0taZU:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=NyFYG_28tbw:QAUImi0taZU:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=NyFYG_28tbw:QAUImi0taZU:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=NyFYG_28tbw:QAUImi0taZU:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=NyFYG_28tbw:QAUImi0taZU:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=NyFYG_28tbw:QAUImi0taZU:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=NyFYG_28tbw:QAUImi0taZU:l6gmwiTKsz0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=NyFYG_28tbw:QAUImi0taZU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=NyFYG_28tbw:QAUImi0taZU:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=NyFYG_28tbw:QAUImi0taZU:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FunctionalFun/~4/NyFYG_28tbw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.functionalfun.net/feeds/367052749553595012/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.functionalfun.net/2009/06/magnetic-mums.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/367052749553595012?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/367052749553595012?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FunctionalFun/~3/NyFYG_28tbw/magnetic-mums.html" title="Magnetic Personalities" /><author><name>Sam</name><uri>http://www.blogger.com/profile/01345100698738870730</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09416134415683403048" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.functionalfun.net/2009/06/magnetic-mums.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A08ESXoyfip7ImA9WxJXFks.&quot;"><id>tag:blogger.com,1999:blog-7577421612120825312.post-8259535339669419670</id><published>2009-06-10T21:45:00.001+01:00</published><updated>2009-06-10T22:36:48.496+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-10T22:36:48.496+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Software" /><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><category scheme="http://www.blogger.com/atom/ns#" term=".Net" /><category scheme="http://www.blogger.com/atom/ns#" term="Links" /><title>Managed Memory leaks and their solutions</title><content type="html">&lt;p&gt;It’s a myth that managed code does not suffer from memory leaks. Managed code is as capable of springing leaks as unmanaged, though fortunately, the leaks themselves are not nearly so pernicious. In managed code, leaks are not the result of forgetting to deallocate memory – the Garbage Collector is pretty much infallible in that respect. Rather, the leaks are almost always the result of an object subscribing to an event on another object with a longer lifetime. This results in the longer-lived Grandpa object grasping so tightly to the reference to the shorter-lived object (so that it can notify it of events) that the Garbage Collector dare not clean up the whippersnapper.&lt;/p&gt;  &lt;p&gt;Such situations can easily be detected using one of the many &lt;a href="http://stackoverflow.com/questions/3927/what-are-some-good-net-profilers"&gt;memory profilers&lt;/a&gt; around (I’ve used, and can heartily recommend JetBrains &lt;a href="http://www.jetbrains.com/profiler/"&gt;dotTrace&lt;/a&gt;; I’ve also heard good things about the new version of RedGate’s &lt;a href="http://www.red-gate.com/products/ants_memory_profiler/index_beta.htm"&gt;Ants Profiler&lt;/a&gt;). These help you identify the objects that you expected to be cleaned up, and then let you trace back to find the villains that are keeping them alive.&lt;/p&gt;  &lt;p&gt;But once you’ve identified the source of the problem, what do you do? Sometimes it’s as easy as remembering to make the short-lived objects unsubscribe from the longer-lived – you can do this if the class implements IDisposable, for instance. Other times, there’s no suitable or natural point at which to do the clean-up. What then?&lt;/p&gt;  &lt;p&gt;That’s the subject of the excellent Code-Project article &lt;a href="http://www.codeproject.com/KB/cs/WeakEvents.aspx"&gt;Weak Events in C#&lt;/a&gt; which explains the problem in more detail and covers the whole range of possible solutions to the problem. Don’t let the title put you off: the solutions don’t compromise on the power of your events – you can still declare &lt;/p&gt;  &lt;p&gt;   &lt;div class="wlWriterEditableSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:9fefe23d-d7d2-4ab8-b26b-fe92fd7f7918" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;pre name="code" class="c#"&gt;public event EventHandler&amp;lt;EventArgs&amp;gt; CountdownToArmagedonStarted&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;

&lt;p&gt;if you want to. Rather, the title refers to the common ingredient in all the solutions, the magical &lt;a href="http://msdn.microsoft.com/en-us/library/system.weakreference.aspx"&gt;WeakReference&lt;/a&gt; class.&lt;/p&gt;

&lt;p&gt;Go read &lt;a href="http://www.codeproject.com/KB/cs/WeakEvents.aspx"&gt;the article&lt;/a&gt;. It will be the best spent fifteen minutes of your day. &lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7577421612120825312-8259535339669419670?l=blog.functionalfun.net'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/p0DF6joyJvZv1zJ88cMyH7cWOoc/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/p0DF6joyJvZv1zJ88cMyH7cWOoc/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/p0DF6joyJvZv1zJ88cMyH7cWOoc/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/p0DF6joyJvZv1zJ88cMyH7cWOoc/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=ae_Z7HSu-fU:LIJDsG_wY0o:VYtfdMxc7SE"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=ae_Z7HSu-fU:LIJDsG_wY0o:VYtfdMxc7SE" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=ae_Z7HSu-fU:LIJDsG_wY0o:8U7eRf_NmwQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=8U7eRf_NmwQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=ae_Z7HSu-fU:LIJDsG_wY0o:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=ae_Z7HSu-fU:LIJDsG_wY0o:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=ae_Z7HSu-fU:LIJDsG_wY0o:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=ae_Z7HSu-fU:LIJDsG_wY0o:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=ae_Z7HSu-fU:LIJDsG_wY0o:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=ae_Z7HSu-fU:LIJDsG_wY0o:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=ae_Z7HSu-fU:LIJDsG_wY0o:l6gmwiTKsz0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=ae_Z7HSu-fU:LIJDsG_wY0o:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=ae_Z7HSu-fU:LIJDsG_wY0o:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=ae_Z7HSu-fU:LIJDsG_wY0o:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FunctionalFun/~4/ae_Z7HSu-fU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.functionalfun.net/feeds/8259535339669419670/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.functionalfun.net/2009/06/managed-memory-leaks-and-their.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/8259535339669419670?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/8259535339669419670?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FunctionalFun/~3/ae_Z7HSu-fU/managed-memory-leaks-and-their.html" title="Managed Memory leaks and their solutions" /><author><name>Sam</name><uri>http://www.blogger.com/profile/01345100698738870730</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09416134415683403048" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.functionalfun.net/2009/06/managed-memory-leaks-and-their.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ck8FRH87eyp7ImA9WxJXFEk.&quot;"><id>tag:blogger.com,1999:blog-7577421612120825312.post-6822059755489377946</id><published>2009-06-08T07:00:00.000+01:00</published><updated>2009-06-08T07:00:15.103+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-08T07:00:15.103+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Math" /><category scheme="http://www.blogger.com/atom/ns#" term="Humour" /><category scheme="http://www.blogger.com/atom/ns#" term="Personal" /><title>Are Biology Students devolving?</title><content type="html">&lt;p&gt;As if she wasn't busy enough bringing up our daughter, and growing the &lt;a href="http://blog.functionalfun.net/2008/12/announcing-new-family-development.html"&gt;new addition to the family&lt;/a&gt;, my wife is a part-time private tutor to several A-Level Biology students (A-Level, for those not from the UK, being the final hurdle students have to clear before University). These students must all have passed their GCSEs before being accepted on to A-Level courses, with exams including core subjects like English and Maths. But you'd never know it from the answers they give as my wife goes over practice exam questions with them.&lt;/p&gt;  &lt;p&gt;Take percentages. One question involved converting a percentage to a frequency: if 5% of the population have the recessive form of gene X, how many is that out of 100? Blank stare. &lt;/p&gt;  &lt;p&gt;Then there was a question about interpreting &lt;a href="http://en.wikipedia.org/wiki/Electrocardiogram" target="_blank"&gt;Echocardiogram&lt;/a&gt; (ECG) traces. You’ll have seen one these in the movies if ever there was a hospital death scene. As the patient breathes his last, the camera invariably pans to an ECG monitor at his bedside. The sound-track turns somber, the sun is blotted out by a cloud, and on the monitor the peaks and troughs of heart activity subside to the infamous flat line. &lt;/p&gt;  &lt;p&gt;On an ECG, the trace shows activity up the vertical axis and time along the horizontal, so to calculate the heart rate (as the question required) you begin by measuring the distance between peaks on the chart to get the duration of each beat. The student could do that - counting blocks was within her skill set. But the next step was to convert that to a rate in beats per minute.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://en.wikipedia.org/wiki/File:12leadECG.jpg"&gt;&lt;img title="ECG Monitor: Photo Credit, Wikipedia" style="display: block; float: none; margin-left: auto; margin-right: auto" height="265" alt="ECG Monitor: Photo Credit, Wikipedia" src="http://lh3.ggpht.com/_Blokl_3SWiA/Sibdp7nJ3sI/AAAAAAAAAc8/6XeeEs16asI/800px-12leadECG%5B7%5D.jpg?imgmax=800" width="607" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&amp;quot;It's not fair that they ask Maths questions in a Biology paper!&amp;quot;, complained the student. My wife was taken aback for a moment – the girl apparently wasn’t joking.&lt;/p&gt;  &lt;p&gt;&amp;quot;So what do you do now?&amp;quot;, my wife prompted once she’d recovered. &lt;/p&gt;  &lt;p&gt;&amp;quot;I don't know&amp;quot;, began the student; then with sudden inspiration: &amp;quot;It's got something to do with 60 hasn't it?&amp;quot;.&lt;/p&gt;  &lt;p&gt;&amp;quot;Well, yes, it has,&amp;quot;, my wife said encouragingly. &amp;quot;You know how long each beat lasts. Now you need to work out how many of those beats will fit in a minute. So what do you do?&amp;quot;&lt;/p&gt;  &lt;p&gt;&amp;quot;Ah, I've got it now&amp;quot;. The student's face lights up. My wife smiles hopefully. &amp;quot;You divide the time by 60!&amp;quot;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7577421612120825312-6822059755489377946?l=blog.functionalfun.net'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/x9DO-Jt3VioNwUwiEorAdCl9lbk/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/x9DO-Jt3VioNwUwiEorAdCl9lbk/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/x9DO-Jt3VioNwUwiEorAdCl9lbk/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/x9DO-Jt3VioNwUwiEorAdCl9lbk/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=C3ZCAd2gkYw:0uxte4hqJ0Q:VYtfdMxc7SE"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=C3ZCAd2gkYw:0uxte4hqJ0Q:VYtfdMxc7SE" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=C3ZCAd2gkYw:0uxte4hqJ0Q:8U7eRf_NmwQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=8U7eRf_NmwQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=C3ZCAd2gkYw:0uxte4hqJ0Q:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=C3ZCAd2gkYw:0uxte4hqJ0Q:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=C3ZCAd2gkYw:0uxte4hqJ0Q:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=C3ZCAd2gkYw:0uxte4hqJ0Q:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=C3ZCAd2gkYw:0uxte4hqJ0Q:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=C3ZCAd2gkYw:0uxte4hqJ0Q:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=C3ZCAd2gkYw:0uxte4hqJ0Q:l6gmwiTKsz0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=C3ZCAd2gkYw:0uxte4hqJ0Q:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=C3ZCAd2gkYw:0uxte4hqJ0Q:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=C3ZCAd2gkYw:0uxte4hqJ0Q:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FunctionalFun/~4/C3ZCAd2gkYw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.functionalfun.net/feeds/6822059755489377946/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.functionalfun.net/2009/06/are-biology-students-devolving.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/6822059755489377946?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/6822059755489377946?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FunctionalFun/~3/C3ZCAd2gkYw/are-biology-students-devolving.html" title="Are Biology Students devolving?" /><author><name>Sam</name><uri>http://www.blogger.com/profile/01345100698738870730</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09416134415683403048" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://blog.functionalfun.net/2009/06/are-biology-students-devolving.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0YDQ3s4eCp7ImA9WxJXEUw.&quot;"><id>tag:blogger.com,1999:blog-7577421612120825312.post-3610156650846852034</id><published>2009-06-04T13:10:00.001+01:00</published><updated>2009-06-04T13:39:32.530+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-04T13:39:32.530+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Software" /><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><category scheme="http://www.blogger.com/atom/ns#" term="ASP.Net" /><category scheme="http://www.blogger.com/atom/ns#" term=".Net" /><title>ASP.Net Quick Tip: Get Web Deployment projects working with Web Application Projects</title><content type="html">&lt;p&gt;Hopefully this will save someone else (or my future self) the couple of hours my colleague and I spent wrestling with ASP.Net to get this to work. &lt;/p&gt;  &lt;p&gt;We have an ASP.Net 3.5 Web Application project and were trying to pair it up with a &lt;a href="http://blogs.msdn.com/webdevtools/archive/2008/01/25/announcing-rtw-of-visual-studio-2008-web-deployment-projects-wdp.aspx"&gt;Web Deployment Project&lt;/a&gt;. This first problem we faced was with ILMerge complaining during the build process for the web deployment project. It said &amp;quot;An error occurred when merging assemblies: ILMerge.Merge: The target assembly 'cwSharp2' lists itself as an external reference.”. We fixed this thanks to a &lt;a href="http://www.west-wind.com/WebLog/posts/2454.aspx#260728"&gt;comment&lt;/a&gt; by JohnC on a &lt;a href="http://www.west-wind.com/WebLog/posts/2454.aspx"&gt;post&lt;/a&gt; by Rick Strahl. You have to make sure that the output assembly for the Web Deployment project is different to the Web Application project – we called ours [Project].Pages.&lt;/p&gt;  &lt;p&gt;The next problem didn’t reveal itself until we actually tried running the website as compiled by the Web Deployment project. When we tried browsing one of the pages we got errors like “&lt;b&gt;Compiler Error Message: &lt;/b&gt;CS0433: The type '**' exists in both '***.dll’ and ‘***.dll'”. I searched, and – &lt;a href="http://bing.com"&gt;bing&lt;/a&gt; – out popped &lt;a href="http://www.tech-archive.net/Archive/DotNet/microsoft.public.dotnet.framework.aspnet/2007-04/msg02987.html"&gt;the answer&lt;/a&gt;: you have to right-click your web application project and click “Convert to Web Application”; doesn’t quite make sense, I know, but it works!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7577421612120825312-3610156650846852034?l=blog.functionalfun.net'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/vqTPzZF1KXMViO498BP_plUYi8k/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/vqTPzZF1KXMViO498BP_plUYi8k/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/vqTPzZF1KXMViO498BP_plUYi8k/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/vqTPzZF1KXMViO498BP_plUYi8k/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=QnQr2DxxWhQ:0-06WOhDWzM:VYtfdMxc7SE"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=QnQr2DxxWhQ:0-06WOhDWzM:VYtfdMxc7SE" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=QnQr2DxxWhQ:0-06WOhDWzM:8U7eRf_NmwQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=8U7eRf_NmwQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=QnQr2DxxWhQ:0-06WOhDWzM:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=QnQr2DxxWhQ:0-06WOhDWzM:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=QnQr2DxxWhQ:0-06WOhDWzM:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=QnQr2DxxWhQ:0-06WOhDWzM:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=QnQr2DxxWhQ:0-06WOhDWzM:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=QnQr2DxxWhQ:0-06WOhDWzM:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=QnQr2DxxWhQ:0-06WOhDWzM:l6gmwiTKsz0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=QnQr2DxxWhQ:0-06WOhDWzM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=QnQr2DxxWhQ:0-06WOhDWzM:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=QnQr2DxxWhQ:0-06WOhDWzM:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FunctionalFun/~4/QnQr2DxxWhQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.functionalfun.net/feeds/3610156650846852034/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.functionalfun.net/2009/06/aspnet-quick-tip-get-web-deployment.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/3610156650846852034?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/3610156650846852034?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FunctionalFun/~3/QnQr2DxxWhQ/aspnet-quick-tip-get-web-deployment.html" title="ASP.Net Quick Tip: Get Web Deployment projects working with Web Application Projects" /><author><name>Sam</name><uri>http://www.blogger.com/profile/01345100698738870730</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09416134415683403048" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://blog.functionalfun.net/2009/06/aspnet-quick-tip-get-web-deployment.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ak4FRH84fCp7ImA9WxJQFEg.&quot;"><id>tag:blogger.com,1999:blog-7577421612120825312.post-5672671568115248892</id><published>2009-05-27T17:43:00.001+01:00</published><updated>2009-05-27T22:15:15.134+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-05-27T22:15:15.134+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Software" /><category scheme="http://www.blogger.com/atom/ns#" term="Silverlight" /><category scheme="http://www.blogger.com/atom/ns#" term=".Net" /><title>Silverlight Utility to decode Roman Numerals and spell out numbers</title><content type="html">&lt;p&gt;&lt;a href="http://functionalfun.web.officelive.com/numberconverter.aspx"&gt;&lt;img title="Utility to decode roman numerals and spell out numbers" style="display: inline; margin: 0px 10px 0px 0px" height="213" alt="Utility to decode roman numerals and spell out numbers" src="http://lh5.ggpht.com/_Blokl_3SWiA/Sh1tumU9a4I/AAAAAAAAAc4/KzuQgTZTvv8/CropperCapture%5B56%5D%5B6%5D.png?imgmax=800" width="317" align="left" /&gt;&lt;/a&gt; I’ve had another chance to play around with &lt;a href="http://silverlight.net/" target="_blank"&gt;Silverlight&lt;/a&gt; 2 over the last two days. The result: a new version of my &lt;a href="http://functionalfun.web.officelive.com/numberconverter.aspx" target="_blank"&gt;utility to convert numbers to words&lt;/a&gt;. I’ve now added the ability to convert to and from Roman Numerals, making it substantially more useful – if you’re a Roman citizen caught in a time warp. Go &lt;a href="http://functionalfun.web.officelive.com/numberconverter.aspx" target="_blank"&gt;try it&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;I love the way Silverlight lets you run standard C# in the browser – generics, LINQ and all. The code for the conversion algorithms comes straight from two of my Project Euler posts, &lt;a href="http://blog.functionalfun.net/2008/08/project-euler-problem-17-converting.html" target="_blank"&gt;Converting Numbers to Words&lt;/a&gt; and &lt;a href="http://blog.functionalfun.net/2009/01/project-euler-89-converting-to-and-from.html" target="_blank"&gt;Converting to and from Roman Numerals&lt;/a&gt;. From my limited experiment, the &lt;a href="http://msdn.microsoft.com/en-us/magazine/dd458800.aspx" target="_blank"&gt;Model-View-View Model&lt;/a&gt; pattern also appears to work pretty much as it does in WPF, though data binding in Silverlight is not so sophisticated. For example, there is no &lt;a href="http://msdn.microsoft.com/en-us/library/system.windows.data.binding.updatesourcetrigger.aspx" target="_blank"&gt;UpdateSourceTrigger&lt;/a&gt; mode in Silverlight, so when you want a TextBox to update its data source every time the text changes you have to resort to &lt;a href="http://silverlight.net/forums/t/11547.aspx" target="_blank"&gt;a hack&lt;/a&gt; (switching focus away from the TextBox, then back again).&lt;/p&gt;  &lt;h4&gt;&lt;/h4&gt;  &lt;h4&gt;Unit Testing Silverlight&lt;/h4&gt;  &lt;p&gt;I’ve become quite a fan of unit testing over the last 9 months or so of my latest project, and I wanted to make sure we’ll be able to carry on the practice in Silverlight. Turns out it can be done, but choices are more limited than on the full CLR – mostly due to Silverlight only running in the browser (unless you are &lt;a href="http://clrguru.blogspot.com/2009/01/taming-coreclr-part-1.html" target="_blank"&gt;devious&lt;/a&gt;). There’s &lt;a href="http://cthru.codeplex.com/" target="_blank"&gt;SilverUnit&lt;/a&gt;, but that’s built on top of &lt;a href="http://www.typemock.com/" target="_blank"&gt;Typemock Isolator&lt;/a&gt; which commercial users have to pay for. Or there’s &lt;a href="http://www.jeff.wilcox.name/2008/03/silverlight2-unit-testing/" target="_blank"&gt;Silverlight Unit Testing framework&lt;/a&gt; from Microsoft, which you can get free as part of the &lt;a href="http://codeplex.com/Silverlight" target="_blank"&gt;Silverlight Toolkit&lt;/a&gt; on &lt;a href="http://codeplex.com/" target="_blank"&gt;Codeplex&lt;/a&gt;. I went with the free option. &lt;/p&gt;  &lt;p&gt;Creating tests with Silverlight Unit Testing Framework is straightforward - you just decorate your classes and test methods with attributes, just as with other Unit Testing frameworks. At the moment though, options for running the tests are limited: you pretty much have to use the provided method, that runs through all the tests in a browser window. My colleague is currently trying out a technique using a &lt;a href="http://blog.lab49.com/archives/2292" target="_blank"&gt;powershell script to automate Internet Explorer&lt;/a&gt; so that we can include the Unit Tests on our Continuous Integration Server; also check out &lt;a href="http://odin.codeplex.com" target="_blank"&gt;Odin&lt;/a&gt;, a promising looking project on CodePlex that aims to get the tests running from Resharper.&lt;/p&gt;  &lt;p&gt;Oh, and one last thing. Did you know that Microsoft provide &lt;a href="http://streaming.live.com"&gt;free hosting for Silverlight applications&lt;/a&gt; – 10 whole Gigabytes? And with &lt;a href="http://www.officelive.com"&gt;Office Live&lt;/a&gt; you can get a website hosted for you, but using your own domain name – again for free. That’s how I’m hosting &lt;a href="http://functionalfun.web.officelive.com/numberconverter.aspx"&gt;the utility&lt;/a&gt;.&lt;/p&gt;  &lt;h4&gt;&lt;/h4&gt;  &lt;h4&gt;Get the Code&lt;/h4&gt;  &lt;p&gt;I’ve put &lt;a href="http://code.msdn.microsoft.com/numeraldecoder" target="_blank"&gt;all the code&lt;/a&gt; for this little utility on MSDN Code Gallery for your hacking pleasure.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7577421612120825312-5672671568115248892?l=blog.functionalfun.net'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/sYZH8njnkxBGbBETmjiP1UBaDQw/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/sYZH8njnkxBGbBETmjiP1UBaDQw/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/sYZH8njnkxBGbBETmjiP1UBaDQw/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/sYZH8njnkxBGbBETmjiP1UBaDQw/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=17IM037hYvo:jBSxPYMvJhk:VYtfdMxc7SE"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=17IM037hYvo:jBSxPYMvJhk:VYtfdMxc7SE" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=17IM037hYvo:jBSxPYMvJhk:8U7eRf_NmwQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=8U7eRf_NmwQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=17IM037hYvo:jBSxPYMvJhk:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=17IM037hYvo:jBSxPYMvJhk:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=17IM037hYvo:jBSxPYMvJhk:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=17IM037hYvo:jBSxPYMvJhk:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=17IM037hYvo:jBSxPYMvJhk:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=17IM037hYvo:jBSxPYMvJhk:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=17IM037hYvo:jBSxPYMvJhk:l6gmwiTKsz0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=17IM037hYvo:jBSxPYMvJhk:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=17IM037hYvo:jBSxPYMvJhk:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=17IM037hYvo:jBSxPYMvJhk:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FunctionalFun/~4/17IM037hYvo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.functionalfun.net/feeds/5672671568115248892/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.functionalfun.net/2009/05/silverlight-utility-to-decode-roman.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/5672671568115248892?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/5672671568115248892?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FunctionalFun/~3/17IM037hYvo/silverlight-utility-to-decode-roman.html" title="Silverlight Utility to decode Roman Numerals and spell out numbers" /><author><name>Sam</name><uri>http://www.blogger.com/profile/01345100698738870730</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09416134415683403048" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.functionalfun.net/2009/05/silverlight-utility-to-decode-roman.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUEFQXg_eCp7ImA9WxJSEUg.&quot;"><id>tag:blogger.com,1999:blog-7577421612120825312.post-8848884229752635492</id><published>2009-05-01T07:00:00.000+01:00</published><updated>2009-05-01T07:00:10.640+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-05-01T07:00:10.640+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Functional Programming" /><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><category scheme="http://www.blogger.com/atom/ns#" term="LINQ" /><category scheme="http://www.blogger.com/atom/ns#" term=".Net" /><title>Practical LINQ #3: Compacting ranges of numbers</title><content type="html">&lt;p&gt;Here’s a problem that has popped up several times in one guise or another during the six years of my career: &lt;/p&gt;  &lt;p&gt;&lt;em&gt;Given a list of numbers, present it to the user in its most compact form. &lt;/em&gt;&lt;/p&gt;  &lt;p&gt;So if you have 1, 3, 4, 5, 9, 11, 12, 13 it should be presented as 1, 3 – 5, 9, 11 – 13. It’s what your brain does automatically when you fill out the “Selected Pages” box in the Print dialog of Microsoft Word.&lt;/p&gt;  &lt;p&gt;I’m sure you can imagine for yourself the kind of &lt;em&gt;for&lt;/em&gt;-loop I crafted the last time I solved this problem. This time I wanted to make life more interesting. &lt;/p&gt;  &lt;p&gt;The first thing is to make sure the numbers are marshalled in ascending order, with no duplicates in the ranks:&lt;/p&gt;  &lt;div class="wlWriterEditableSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:d02d6877-b0a9-49d3-a353-3c9395969ac9" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;pre name="code" class="c#"&gt;var preparedList = numbers.Distinct().OrderBy(x =&amp;gt; x);&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;For the next step, I imagined into being a little Scanner class, with a nice fluent interface. I wrote down the following code, which was how I wanted the Scanner to work; then, with &lt;a href="http://www.jetbrains.com/resharper/" target="_blank"&gt;Resharper&lt;/a&gt; pointing out my omissions in glaring red text, I implemented the concepts to make it work:&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;div class="wlWriterEditableSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:be1e4034-7867-4eed-aca9-66efc343328e" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;pre name="code" class="c#"&gt;public IEnumerable&amp;lt;Range&amp;gt; Compact(IEnumerable&amp;lt;int&amp;gt; numbers)
{
    var preparedList = numbers.Distinct().OrderBy(x =&amp;gt; x);

    var scanner = new Scanner&amp;lt;int, Range&amp;gt;();

    scanner.ConfigurePattern()
        .StartMatchingWhenAny()
        .ContinueMatchingWhile((nextItem, matchedItems) =&amp;gt; nextItem == matchedItems.Last() + 1)
        .Output(details =&amp;gt; new Range(
                                    details.MatchedItems.First(),
                                    details.MatchedItems.Last()));

    return scanner.Scan(preparedList);
}

&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The idea is for the Scanner to walk a sequence of objects (ints in this case), producing from it a sequence of tokens (here, &lt;em&gt;Range&lt;/em&gt; objects – simple structs with &lt;em&gt;First&lt;/em&gt; and &lt;em&gt;Last&lt;/em&gt; properties). The Scanner produces its output by matching patterns of contiguous input elements. The patterns are configured using a fluent interface: &lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;the condition that must be met in order to start matching this pattern (any integer is accepted at the start of this simple pattern)&lt;/li&gt;

  &lt;li&gt;which items are considered part of the pattern: here an integer is accepted if it is only one bigger than the previous matched integer&lt;/li&gt;

  &lt;li&gt;how to generate a token from the matched part of the sequence&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The internal workings of the scanner aren’t terribly interesting. See the download link below if you’re desperate for a look.&lt;/p&gt;

&lt;p&gt;Now don’t laugh: &lt;a href="http://msdn.microsoft.com/en-us/library/57a79xd0.aspx" target="_blank"&gt;String.Join&lt;/a&gt; is my discovery of the week. It concatenates an array of strings, putting a separator of your choice between them; leaving you free to fry bigger fish than &lt;a href="http://blogs.msdn.com/ericlippert/archive/2009/04/13/restating-the-problem.aspx" target="_blank"&gt;how to put a comma after every item except the last&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So my final answer looks like this:&lt;/p&gt;

&lt;p&gt;
  &lt;div class="wlWriterEditableSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:df161f25-5936-4057-99a9-4096746071df" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;pre name="code" class="c#"&gt;var numbers = new[] {1, 3, 4, 5, 9, 11, 12, 13};

var compacter = new RangeCompacter();
var ranges = compacter.Compact(numbers);

// create a pretty string, each range or number separated by a comma
var display = string.Join(
    ", ", 
    ranges
    .Select(range =&amp;gt; range.ToString())
    .ToArray());

Assert.AreEqual("1, 3 - 5, 9, 11 - 13", display);&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;

&lt;p&gt;I’ve put all the code, including my Scanner class, on &lt;a href="http://code.msdn.microsoft.com/fluentscanner" target="_blank"&gt;Code Gallery&lt;/a&gt;; there’s even a sprinkling of unit tests! If you find any other uses for it, do let me know.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7577421612120825312-8848884229752635492?l=blog.functionalfun.net'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/MF07ukKyHWV5CdGgKG3X654SZhk/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/MF07ukKyHWV5CdGgKG3X654SZhk/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/MF07ukKyHWV5CdGgKG3X654SZhk/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/MF07ukKyHWV5CdGgKG3X654SZhk/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=oWuGAozhBlw:Ss8NJYxvo9o:VYtfdMxc7SE"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=oWuGAozhBlw:Ss8NJYxvo9o:VYtfdMxc7SE" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=oWuGAozhBlw:Ss8NJYxvo9o:8U7eRf_NmwQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=8U7eRf_NmwQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=oWuGAozhBlw:Ss8NJYxvo9o:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=oWuGAozhBlw:Ss8NJYxvo9o:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=oWuGAozhBlw:Ss8NJYxvo9o:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=oWuGAozhBlw:Ss8NJYxvo9o:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=oWuGAozhBlw:Ss8NJYxvo9o:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=oWuGAozhBlw:Ss8NJYxvo9o:l6gmwiTKsz0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=oWuGAozhBlw:Ss8NJYxvo9o:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=oWuGAozhBlw:Ss8NJYxvo9o:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=oWuGAozhBlw:Ss8NJYxvo9o:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FunctionalFun/~4/oWuGAozhBlw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.functionalfun.net/feeds/8848884229752635492/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.functionalfun.net/2009/05/practical-linq-3-compacting-ranges-of.html#comment-form" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/8848884229752635492?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/8848884229752635492?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FunctionalFun/~3/oWuGAozhBlw/practical-linq-3-compacting-ranges-of.html" title="Practical LINQ #3: Compacting ranges of numbers" /><author><name>Sam</name><uri>http://www.blogger.com/profile/01345100698738870730</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09416134415683403048" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">3</thr:total><feedburner:origLink>http://blog.functionalfun.net/2009/05/practical-linq-3-compacting-ranges-of.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUMNSHg9cSp7ImA9WxJSEE8.&quot;"><id>tag:blogger.com,1999:blog-7577421612120825312.post-1842526601777456575</id><published>2009-04-28T22:03:00.001+01:00</published><updated>2009-04-29T17:44:59.669+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-29T17:44:59.669+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Personal" /><title>Broadband woes and customer service triumphs</title><content type="html">&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_Blokl_3SWiA/SfiDR5rSkeI/AAAAAAAAAcw/8Acr0K4kouo/s1600-h/WirelessRouter%5B8%5D.jpg"&gt;&lt;img style="margin: 0px 10px 0px 0px; display: inline" title="WirelessRouter" alt="WirelessRouter" align="left" src="http://lh5.ggpht.com/_Blokl_3SWiA/SfiDSMcw3EI/AAAAAAAAAc0/5-Sb7uK7WwI/WirelessRouter_thumb%5B12%5D.jpg?imgmax=800" width="116" height="194" /&gt;&lt;/a&gt;My Broadband router died the other day. One night it worked, the next morning – caput! No lights on the front panel, no response even when I prodded the reset button with a pen. Our house seems to be an &lt;a href="http://blog.functionalfun.net/2008/08/sudden-onset-digital-amnesia.html" target="_blank"&gt;unhealthy environment for electronics&lt;/a&gt;. I blame my wife: when she was at university, she could crash a computer just by sitting down and putting her hand to the mouse. &lt;/p&gt;  &lt;p&gt;But my luck was in. This was a &lt;a href="http://belkin.com/" target="_blank"&gt;Belkin&lt;/a&gt; router, and it came with a lifetime guarantee – and not a gnat’s lifetime either, as it turned out. &lt;/p&gt;  &lt;p&gt;I suspected a fried power supply, so I got chatting to technical support (Live Chat does an excellent of rendering an Indian accent intelligible to British eyes!), intending to ask them to replace it. I got more than I bargained for. &lt;/p&gt;  &lt;p&gt;Having cleared the hurdle of First Line support, Second Line agreed that they would give me a replacement – of the whole router. In fact, they would give me an upgrade, since the model I had was obsolete. And to top it all, they emailed me a postage-paid label by which to return my old router.&lt;/p&gt;  &lt;p&gt;Now get this: I bought the router for £20 second-hand from a colleague more than a year ago, yet that didn’t concern Belkin – at no point did they ask for so much as a whiff of a proof of purchase. &lt;/p&gt;  &lt;p&gt;The router duly arrived, I plugged it in, and – no connection. I borrowed a friend’s router – no connection on that either. Clearly my line had rotted from lack of use. &lt;/p&gt;  &lt;p&gt;That was when I discovered the magical &lt;a href="http://www.broadbandbuyer.co.uk/Shop/ShopDetail.asp?ProductID=7256" target="_blank"&gt;iPlate&lt;/a&gt; from BT. It’s a widget that costs less than a tenner, that really does &lt;a href="http://www.youtube.com/watch?v=JbHbOJIsTPw" target="_blank"&gt;install in minutes&lt;/a&gt; (on top of your home’s master socket), and it brought my line back from the dead. It works, I’m told, by &lt;a href="http://www.jarviser.co.uk/jarviser/broadbandspeed.html" target="_blank"&gt;cutting out the bell wire&lt;/a&gt; (used, in the olden days, to ring your phone’s bell, but now defunct and the cause of much interference on the line). My download speed is pretty much as it was before, but my upload speed has almost doubled!&lt;/p&gt;  &lt;p&gt;So now I don’t even have dead Broadband as an excuse for not updating my blog in over a month!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7577421612120825312-1842526601777456575?l=blog.functionalfun.net'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/y2LWl0KtEO4AG59AYcyllbplLzw/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/y2LWl0KtEO4AG59AYcyllbplLzw/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/y2LWl0KtEO4AG59AYcyllbplLzw/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/y2LWl0KtEO4AG59AYcyllbplLzw/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=gM9hWIsW874:OrQ-Pis-ZmU:VYtfdMxc7SE"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=gM9hWIsW874:OrQ-Pis-ZmU:VYtfdMxc7SE" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=gM9hWIsW874:OrQ-Pis-ZmU:8U7eRf_NmwQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=8U7eRf_NmwQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=gM9hWIsW874:OrQ-Pis-ZmU:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=gM9hWIsW874:OrQ-Pis-ZmU:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=gM9hWIsW874:OrQ-Pis-ZmU:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=gM9hWIsW874:OrQ-Pis-ZmU:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=gM9hWIsW874:OrQ-Pis-ZmU:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=gM9hWIsW874:OrQ-Pis-ZmU:l6gmwiTKsz0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=gM9hWIsW874:OrQ-Pis-ZmU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=gM9hWIsW874:OrQ-Pis-ZmU:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=gM9hWIsW874:OrQ-Pis-ZmU:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FunctionalFun/~4/gM9hWIsW874" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.functionalfun.net/feeds/1842526601777456575/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.functionalfun.net/2009/04/broadband-woes-and-customer-service.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/1842526601777456575?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/1842526601777456575?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FunctionalFun/~3/gM9hWIsW874/broadband-woes-and-customer-service.html" title="Broadband woes and customer service triumphs" /><author><name>Sam</name><uri>http://www.blogger.com/profile/01345100698738870730</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09416134415683403048" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.functionalfun.net/2009/04/broadband-woes-and-customer-service.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUUBQXg4eyp7ImA9WxVbEko.&quot;"><id>tag:blogger.com,1999:blog-7577421612120825312.post-8920076315034597653</id><published>2009-03-27T22:26:00.001Z</published><updated>2009-03-28T21:54:10.633Z</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-28T21:54:10.633Z</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Functional Programming" /><category scheme="http://www.blogger.com/atom/ns#" term="Software" /><category scheme="http://www.blogger.com/atom/ns#" term="LINQ" /><category scheme="http://www.blogger.com/atom/ns#" term=".Net" /><category scheme="http://www.blogger.com/atom/ns#" term="Project Euler" /><title>Project Euler 21: Getting friendly with the Amicable numbers</title><content type="html">&lt;p&gt;I’ve remarked before that to Mathematicians, numbers aren’t, … well, they’re not just numbers. Numbers have personalities. Whilst some are &lt;a href="http://en.wikipedia.org/wiki/Deficient_number" target="_blank"&gt;deficient&lt;/a&gt;, there are others which are &lt;a href="http://mathworld.wolfram.com/AspiringNumber.html" target="_blank"&gt;aspiring&lt;/a&gt;, and a few who are actually &lt;a href="http://en.wikipedia.org/wiki/Perfect_number" target="_blank"&gt;perfect&lt;/a&gt;;&amp;#160; half of them are rather odd, some downright &lt;a href="http://en.wikipedia.org/wiki/Weird_number" target="_blank"&gt;weird&lt;/a&gt;. Of more concern are the &lt;a href="http://mathworld.wolfram.com/OdiousNumber.html" target="_blank"&gt;odious&lt;/a&gt; and &lt;a href="http://mathworld.wolfram.com/EvilNumber.html" target="_blank"&gt;evil&lt;/a&gt; numbers, especially those that consider themselves &lt;a href="http://en.wikipedia.org/wiki/Untouchable_number" target="_blank"&gt;untouchable&lt;/a&gt;&lt;sup&gt;1&lt;/sup&gt;.&lt;/p&gt;  &lt;p&gt;But today we’ll look at a more friendly subject: the &lt;a href="http://en.wikipedia.org/wiki/Amicable_number" target="_blank"&gt;amicable numbers&lt;/a&gt;. What is an amicable number? Let’s get mathematical and define a function d(n) to be the sum of all proper divisors of n (a proper divisor of n is any divisor of n less than n). Then an amicable number a is one which has a friend b where d(a) = b and d(b) = a (note that we don’t allow a to be narcissistic and count itself as a friend). If you do the math (or these days, more realistically, the google search) you’ll find that the first pair of amicable numbers is 220 and 284.&lt;/p&gt;  &lt;p&gt;Amicable numbers have been studied since Greek times: the &lt;a href="http://en.wikipedia.org/wiki/Pythagoreanism" target="_blank"&gt;Pythagoreans&lt;/a&gt; in particular credited these special numbers with mystical powers. They’ve even by tried out as a kind of &lt;a href="http://books.google.co.uk/books?id=52N0JJBspM0C&amp;amp;pg=PA363&amp;amp;lpg=PA363&amp;amp;dq=marriages+based+on+amicable+numbers&amp;amp;source=bl&amp;amp;ots=JAntWy86LU&amp;amp;sig=CX0rkwNVmqCqOfot1hNaZVWUtis&amp;amp;hl=en&amp;amp;ei=-5bOSZ6bCIfKjAfuoNjJCQ&amp;amp;sa=X&amp;amp;oi=book_result&amp;amp;resnum=2&amp;amp;ct=result#PPA363,M1" target="_blank"&gt;mathematical aphrodisiac&lt;/a&gt;:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;El Madshriti, an Arab of the 11th century, experimented with the erotic effects of amicable numbers by giving a beautiful woman the smaller number 220 to eat in the form of a cookie, and himself eating the larger 284! &lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;My sudden interest in amicable numbers was driven by strictly mathematical desire&amp;#160; - to solve &lt;a href="http://projecteuler.net/index.php?section=problems&amp;amp;id=21" target="_blank"&gt;Project Euler 21&lt;/a&gt;&lt;sup&gt;2&lt;/sup&gt;. The problem simply asks us to find the sum of all amicable numbers less than 10000. And in fact, the solution to the problem pretty much falls out of its definition. &lt;/p&gt;  &lt;p&gt;First, I’ll borrow a function from a &lt;a href="http://blog.functionalfun.net/2008/05/project-euler-problem-12.html" target="_blank"&gt;few problems back&lt;/a&gt; that lists all the divisors of a number:&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;div class="wlWriterEditableSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:60669f3c-1342-4680-b616-bfa01eb3306b" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;pre name="code" class="c#"&gt;public static class NumericExtensions
{
    public static IEnumerable&amp;lt;int&amp;gt; Divisors(this int number)
    {
        return (from factor in 1.To((int)Math.Sqrt(number))
                where number.IsDivisibleBy(factor)
                select new [] { factor, number / factor }).Concat();
    }

}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;With that, the answer is straightforward:&lt;/p&gt;

&lt;div class="wlWriterEditableSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:87022ff5-f992-4851-881a-33802be5e357" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;pre name="code" class="c#"&gt;[EulerProblem(21, Title = "Evaluate the sum of all amicable pairs under 10000.")]
public class Problem21
{
    public long Solve()
    {
        Func&amp;lt;int, int&amp;gt; d = n =&amp;gt; n.Divisors().Sum() - n;

        return 	(
				from a in 1.To(10000)
                let b = d(a)
                where a != b &amp;amp;&amp;amp; d(b) == a
                select a
				)
                .Sum();
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As always, full code is available on the &lt;a href="http://code.msdn.microsoft.com/projecteuler" target="_blank"&gt;Project Euler Code Gallery page&lt;/a&gt;.&lt;/p&gt;

&lt;h5&gt;Footnotes&lt;/h5&gt;

&lt;ol&gt;
  &lt;li&gt;If you want to learn more about number personalities, see &lt;a href="http://www.numbergossip.com/list" target="_blank"&gt;this catalogue&lt;/a&gt;. &lt;/li&gt;

  &lt;li&gt;Thanks to Bela Istok who sent me a nice functional solution to the problem, which prompted me to think about how I would solve it myself. &lt;/li&gt;
&lt;/ol&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7577421612120825312-8920076315034597653?l=blog.functionalfun.net'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/qEFOBhOzBrfdzRzmJADZ5HOOkD0/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/qEFOBhOzBrfdzRzmJADZ5HOOkD0/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/qEFOBhOzBrfdzRzmJADZ5HOOkD0/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/qEFOBhOzBrfdzRzmJADZ5HOOkD0/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=PNJd7mc2oY8:-rZ_44VKhP4:VYtfdMxc7SE"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=PNJd7mc2oY8:-rZ_44VKhP4:VYtfdMxc7SE" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=PNJd7mc2oY8:-rZ_44VKhP4:8U7eRf_NmwQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=8U7eRf_NmwQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=PNJd7mc2oY8:-rZ_44VKhP4:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=PNJd7mc2oY8:-rZ_44VKhP4:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=PNJd7mc2oY8:-rZ_44VKhP4:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=PNJd7mc2oY8:-rZ_44VKhP4:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=PNJd7mc2oY8:-rZ_44VKhP4:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=PNJd7mc2oY8:-rZ_44VKhP4:l6gmwiTKsz0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=PNJd7mc2oY8:-rZ_44VKhP4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=PNJd7mc2oY8:-rZ_44VKhP4:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=PNJd7mc2oY8:-rZ_44VKhP4:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FunctionalFun/~4/PNJd7mc2oY8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.functionalfun.net/feeds/8920076315034597653/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.functionalfun.net/2009/03/project-euler-21-getting-friendly-with.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/8920076315034597653?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/8920076315034597653?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FunctionalFun/~3/PNJd7mc2oY8/project-euler-21-getting-friendly-with.html" title="Project Euler 21: Getting friendly with the Amicable numbers" /><author><name>Sam</name><uri>http://www.blogger.com/profile/01345100698738870730</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09416134415683403048" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.functionalfun.net/2009/03/project-euler-21-getting-friendly-with.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUAARnk4eSp7ImA9WxVUE00.&quot;"><id>tag:blogger.com,1999:blog-7577421612120825312.post-2018218632164293207</id><published>2009-03-17T14:21:00.001Z</published><updated>2009-03-17T16:35:47.731Z</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-17T16:35:47.731Z</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Blogging" /><category scheme="http://www.blogger.com/atom/ns#" term="Personal" /><title>Functional Fun on Twitter</title><content type="html">&lt;p&gt;I’ve just taken the plunge, and started tweeting on &lt;a href="http://www.twitter.com" target="_blank"&gt;Twitter&lt;/a&gt;, user name &lt;a href="http://twitter.com/samuel_d_jack" target="_blank"&gt;@samuel_d_jack&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;There have often been times when I’ve been intrigued or amused by something, but haven’t felt sufficiently creative to make a full blog post out of it: micro-blogging on Twitter seems to be the ideal solution.&lt;/p&gt;  &lt;p&gt;I’ve added my Twitter feed to the right-hand side of my blog; and if you don’t find my drivel to be too deleterious you can even subscribe to the &lt;a href="http://twitter.com/statuses/user_timeline/16804503.rss" target="_blank"&gt;RSS feed&lt;/a&gt;.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7577421612120825312-2018218632164293207?l=blog.functionalfun.net'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/P1bKO4qRmA3HLFZyXhSP9mXwQ3w/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/P1bKO4qRmA3HLFZyXhSP9mXwQ3w/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/P1bKO4qRmA3HLFZyXhSP9mXwQ3w/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/P1bKO4qRmA3HLFZyXhSP9mXwQ3w/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=wDXzVRso8J0:Vlkh7-gdqWk:VYtfdMxc7SE"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=wDXzVRso8J0:Vlkh7-gdqWk:VYtfdMxc7SE" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=wDXzVRso8J0:Vlkh7-gdqWk:8U7eRf_NmwQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=8U7eRf_NmwQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=wDXzVRso8J0:Vlkh7-gdqWk:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=wDXzVRso8J0:Vlkh7-gdqWk:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=wDXzVRso8J0:Vlkh7-gdqWk:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=wDXzVRso8J0:Vlkh7-gdqWk:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=wDXzVRso8J0:Vlkh7-gdqWk:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=wDXzVRso8J0:Vlkh7-gdqWk:l6gmwiTKsz0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=wDXzVRso8J0:Vlkh7-gdqWk:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=wDXzVRso8J0:Vlkh7-gdqWk:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=wDXzVRso8J0:Vlkh7-gdqWk:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FunctionalFun/~4/wDXzVRso8J0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.functionalfun.net/feeds/2018218632164293207/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.functionalfun.net/2009/03/functional-fun-on-twitter.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/2018218632164293207?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/2018218632164293207?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FunctionalFun/~3/wDXzVRso8J0/functional-fun-on-twitter.html" title="Functional Fun on Twitter" /><author><name>Sam</name><uri>http://www.blogger.com/profile/01345100698738870730</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09416134415683403048" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://blog.functionalfun.net/2009/03/functional-fun-on-twitter.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkEFQ3c-cSp7ImA9WxVVF0U.&quot;"><id>tag:blogger.com,1999:blog-7577421612120825312.post-4245815365937168177</id><published>2009-03-11T14:00:00.001Z</published><updated>2009-03-11T14:10:12.959Z</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-11T14:10:12.959Z</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Humour" /><category scheme="http://www.blogger.com/atom/ns#" term="Software" /><title>Leaky Abstractions at the Petrol Pump</title><content type="html">&lt;p&gt;Even as a software developer, I'm still ocassionally surprised when events remind me that Spolsky's &lt;a href="http://www.joelonsoftware.com/articles/LeakyAbstractions.html"&gt;Law of Leaky Abstractions&lt;/a&gt; applies to hardware as much as to software.&lt;/p&gt;&lt;p&gt;Here's an example from my holidays last year, when I went to fill up with petrol (how can you Americans call it &lt;span class="Apple-style-span" style="font-style: italic;"&gt;gas&lt;/span&gt; when it's clearly a liquid?):&lt;/p&gt;&lt;p&gt;&lt;img src="http://2.bp.blogspot.com/_Blokl_3SWiA/SbfCeZDLjvI/AAAAAAAAAck/m362mNzMdbI/s400/BSODPumpPhoto_thumb.jpg" style="cursor:pointer; cursor:hand;width: 400px; height: 317px;" border="0" alt="" id="BLOGGER_PHOTO_ID_5311928112882880242" /&gt;
&lt;/p&gt;&lt;p&gt;Any non-technical motorist who peered at the tiny writing on that blue screen and read "DRIVER_ERQL_NOT_LESS_OR_EQUAL" would surely feeel that he's being blamed for the failure, but what did he do wrong? Sounds like he failed some important existential test.&lt;/p&gt;&lt;p&gt;I'm clearly not the only one who enjoys spotting &lt;a href="http://en.wikipedia.org/wiki/Blue_Screen_of_Death"&gt;BSOD&lt;/a&gt;s in the wild: Miguel Carrasco has put together a &lt;a href="http://www.miguelcarrasco.net/miguelcarrasco/2006/10/blue_screen_of_.html"&gt;Blue Screen of Death Top Ten&lt;/a&gt;. And on Gizmodo they have a snapshot of a &lt;a href="http://gizmodo.com/5035456/blue-screen-of-death-strikes-birds-nest-during-opening-ceremonies-torch-lighting"&gt;BSOD that appeared in the Stadium during the Opening Ceremony&lt;/a&gt; at the 2008 Olympic games.&lt;/p&gt;  &lt;p&gt;&lt;span class="Apple-style-span" style="color: rgb(85, 26, 139); text-decoration: underline;"&gt;
&lt;/span&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7577421612120825312-4245815365937168177?l=blog.functionalfun.net'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/ZZPezPTO_fiCUOqNIx4DmrIc1GE/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/ZZPezPTO_fiCUOqNIx4DmrIc1GE/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/ZZPezPTO_fiCUOqNIx4DmrIc1GE/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/ZZPezPTO_fiCUOqNIx4DmrIc1GE/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=VVRrOvJon4k:DmoLRgU4It0:VYtfdMxc7SE"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=VVRrOvJon4k:DmoLRgU4It0:VYtfdMxc7SE" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=VVRrOvJon4k:DmoLRgU4It0:8U7eRf_NmwQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=8U7eRf_NmwQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=VVRrOvJon4k:DmoLRgU4It0:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=VVRrOvJon4k:DmoLRgU4It0:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=VVRrOvJon4k:DmoLRgU4It0:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=VVRrOvJon4k:DmoLRgU4It0:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=VVRrOvJon4k:DmoLRgU4It0:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=VVRrOvJon4k:DmoLRgU4It0:l6gmwiTKsz0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=VVRrOvJon4k:DmoLRgU4It0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=VVRrOvJon4k:DmoLRgU4It0:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=VVRrOvJon4k:DmoLRgU4It0:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FunctionalFun/~4/VVRrOvJon4k" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.functionalfun.net/feeds/4245815365937168177/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.functionalfun.net/2008/09/leak-abstractions-at-petrol-pump.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/4245815365937168177?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/4245815365937168177?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FunctionalFun/~3/VVRrOvJon4k/leak-abstractions-at-petrol-pump.html" title="Leaky Abstractions at the Petrol Pump" /><author><name>Sam</name><uri>http://www.blogger.com/profile/01345100698738870730</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09416134415683403048" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_Blokl_3SWiA/SbfCeZDLjvI/AAAAAAAAAck/m362mNzMdbI/s72-c/BSODPumpPhoto_thumb.jpg" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://blog.functionalfun.net/2008/09/leak-abstractions-at-petrol-pump.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkcEQXk6fip7ImA9WxVVEUg.&quot;"><id>tag:blogger.com,1999:blog-7577421612120825312.post-878360652277382876</id><published>2009-03-04T07:00:00.000Z</published><updated>2009-03-04T07:00:00.716Z</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-04T07:00:00.716Z</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Functional Programming" /><category scheme="http://www.blogger.com/atom/ns#" term="Software" /><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><category scheme="http://www.blogger.com/atom/ns#" term="LINQ" /><category scheme="http://www.blogger.com/atom/ns#" term=".Net" /><title>Practical LINQ #2: Reporting duplicate names</title><content type="html">&lt;p&gt;So my Widget editor can helpfully &lt;a title="Practical LINQ: Generating the next default name" href="http://blog.functionalfun.net/2009/02/practical-linq-generating-next-default.html" target="_blank"&gt;suggest default names&lt;/a&gt;, but it also lets users change the names of widgets. Ohh! Danger ahead: what if they give two (or more) widgets the same name? We can’t have that! The poor dears might confuse themselves. So we better make sure we warn them; that means we have to write code to detect duplicate names. And that gives me another opportunity to show some elegant LINQy C# for solving this real-life problem.&lt;/p&gt;  &lt;p&gt;My requirements are simple: I want to generate an error for all widgets with a shared name, except for the first one with that name – no point in overburdening a user with error messages. I also want to ignore Widgets without a name – I’ve got another rule that deals with them.&lt;/p&gt;  &lt;p&gt;The code is straightforward: group the widgets by name, and ignore any groups containing just one widget. Then for each group generate error messages for all items except the first. Translating that into proper English:&lt;/p&gt;  &lt;div class="wlWriterEditableSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:1029b48e-b2a8-48e5-95d7-90dc75290b51" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;pre name="code" class="c#"&gt;private static IEnumerable&amp;lt;TMessage&amp;gt; DetectDuplicates&amp;lt;T,TMessage&amp;gt;(IEnumerable&amp;lt;T&amp;gt; instances, Func&amp;lt;T, string&amp;gt; nameSelector, Func&amp;lt;T, TMessage&amp;gt; messageGenerator)
{
   var groupedDuplicates = instances
       .GroupBy(nameSelector)
       .Where(group =&amp;gt; group.Count() &amp;gt; 1 &amp;amp;&amp;amp; !string.IsNullOrEmpty(group.Key));

   var errors = groupedDuplicates
       .SelectMany(group =&amp;gt; group.
                                Skip(1)
                                .Select(messageGenerator));

   return errors;
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;All the angle brackets in the method signature can mean only one thing: I’ve made the method generic, so it doesn’t just work with my Widgets; it will work with anything that has a property vaguely resembling a name. Along with your list of instances, you pass in a function that can extract a name from each of your objects, and a function that will generate the appropriate message for each duplicate. In fact it doesn’t just have to a message: you could return a rich error object if you wanted to be really sophisticated.&lt;/p&gt;

&lt;p&gt;Here’s an example&lt;sup&gt;1&lt;/sup&gt;:&lt;/p&gt;

&lt;div class="wlWriterEditableSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:82be4e01-2fab-400b-8432-6d5add052d61" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;pre name="code" class="c#"&gt;static void Main()
{
   var widgets = new[]
                     {
                         new Widget {Name = "Super"},
                         new Widget {Name = "Competent"},
                         new Widget {Name = "Competent"}
                     };

   var errors = DetectDuplicates(
       widgets,
       w =&amp;gt; w.Name,
       w =&amp;gt; "There's already a widget called " + w.Name + ". Be more original!");

   foreach (var error in errors)
   {
       Console.WriteLine(error);
   }

   Console.ReadLine();
}&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;Footnotes&lt;/h4&gt;

&lt;ol&gt;
 &lt;li&gt;The name of one of the widgets here was inspired by a brand of AEG oven that I spotted the other day: they named them “Competence”. I thought brand names were supposed to be aspirational! &lt;/li&gt;
&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7577421612120825312-878360652277382876?l=blog.functionalfun.net'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/uoEUUa7vHDLEunIVTWkJ9BvvSDg/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/uoEUUa7vHDLEunIVTWkJ9BvvSDg/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/uoEUUa7vHDLEunIVTWkJ9BvvSDg/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/uoEUUa7vHDLEunIVTWkJ9BvvSDg/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=iVSF2Z2AvuU:RwxUHeNGGh4:VYtfdMxc7SE"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=iVSF2Z2AvuU:RwxUHeNGGh4:VYtfdMxc7SE" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=iVSF2Z2AvuU:RwxUHeNGGh4:8U7eRf_NmwQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=8U7eRf_NmwQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=iVSF2Z2AvuU:RwxUHeNGGh4:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=iVSF2Z2AvuU:RwxUHeNGGh4:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=iVSF2Z2AvuU:RwxUHeNGGh4:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=iVSF2Z2AvuU:RwxUHeNGGh4:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=iVSF2Z2AvuU:RwxUHeNGGh4:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=iVSF2Z2AvuU:RwxUHeNGGh4:l6gmwiTKsz0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=iVSF2Z2AvuU:RwxUHeNGGh4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=iVSF2Z2AvuU:RwxUHeNGGh4:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=iVSF2Z2AvuU:RwxUHeNGGh4:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FunctionalFun/~4/iVSF2Z2AvuU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.functionalfun.net/feeds/878360652277382876/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.functionalfun.net/2009/03/practical-linq-2-reporting-duplicate.html#comment-form" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/878360652277382876?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/878360652277382876?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FunctionalFun/~3/iVSF2Z2AvuU/practical-linq-2-reporting-duplicate.html" title="Practical LINQ #2: Reporting duplicate names" /><author><name>Sam</name><uri>http://www.blogger.com/profile/01345100698738870730</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09416134415683403048" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">4</thr:total><feedburner:origLink>http://blog.functionalfun.net/2009/03/practical-linq-2-reporting-duplicate.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0MFRXo9cSp7ImA9WxVVEEU.&quot;"><id>tag:blogger.com,1999:blog-7577421612120825312.post-838331290754265854</id><published>2009-03-03T14:10:00.001Z</published><updated>2009-03-03T14:10:14.469Z</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-03T14:10:14.469Z</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Math" /><category scheme="http://www.blogger.com/atom/ns#" term="Humour" /><title>Happy Holidays</title><content type="html">&lt;p&gt;How will you be celebrating &lt;a href="http://news.cnet.com/8301-11386_3-10186121-76.html?tag=newsEditorsPicksArea.0" target="_blank"&gt;square root day&lt;/a&gt;?&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7577421612120825312-838331290754265854?l=blog.functionalfun.net'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/lXayDV9g5C_KTKBhHIV1tEcCpMQ/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/lXayDV9g5C_KTKBhHIV1tEcCpMQ/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/lXayDV9g5C_KTKBhHIV1tEcCpMQ/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/lXayDV9g5C_KTKBhHIV1tEcCpMQ/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=r-JA16k4vIs:GGcYq7JYZi4:VYtfdMxc7SE"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=r-JA16k4vIs:GGcYq7JYZi4:VYtfdMxc7SE" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=r-JA16k4vIs:GGcYq7JYZi4:8U7eRf_NmwQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=8U7eRf_NmwQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=r-JA16k4vIs:GGcYq7JYZi4:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=r-JA16k4vIs:GGcYq7JYZi4:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=r-JA16k4vIs:GGcYq7JYZi4:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=r-JA16k4vIs:GGcYq7JYZi4:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=r-JA16k4vIs:GGcYq7JYZi4:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=r-JA16k4vIs:GGcYq7JYZi4:l6gmwiTKsz0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=r-JA16k4vIs:GGcYq7JYZi4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=r-JA16k4vIs:GGcYq7JYZi4:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=r-JA16k4vIs:GGcYq7JYZi4:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FunctionalFun/~4/r-JA16k4vIs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.functionalfun.net/feeds/838331290754265854/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.functionalfun.net/2009/03/happy-holidays.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/838331290754265854?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/838331290754265854?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FunctionalFun/~3/r-JA16k4vIs/happy-holidays.html" title="Happy Holidays" /><author><name>Sam</name><uri>http://www.blogger.com/profile/01345100698738870730</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09416134415683403048" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.functionalfun.net/2009/03/happy-holidays.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0AGR344cSp7ImA9WxVaGEQ.&quot;"><id>tag:blogger.com,1999:blog-7577421612120825312.post-6332298200184677100</id><published>2009-02-28T21:50:00.001Z</published><updated>2009-04-16T17:35:26.039+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-16T17:35:26.039+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="PDC 2008" /><category scheme="http://www.blogger.com/atom/ns#" term="Software" /><category scheme="http://www.blogger.com/atom/ns#" term=".Net" /><title>Maestro: A new .Net language for parallel programming from Microsoft</title><content type="html">&lt;p&gt;How did I miss this? At PDC 2008 (in the Parallel Symposium, apparently), Microsoft started talking about a new language that may be joining the .Net family. Continuing the musical theme of certain other languages, this one is called Maestro. &lt;/p&gt;  &lt;p&gt;According to an &lt;a href="http://www.ddj.com/go-parallel/article/showArticle.jhtml?articleID=214502187" target="_blank"&gt;article in Dr Dobbs Journal&lt;/a&gt;, Maestro is a special purpose language designed to simplify the writing of scalable parallel programs. It will integrate with other .Net components, and it seems that the intention is for the compute-intensive parts of applications to be written in Maestro, while the staple .Net languages continue to power the rest.&lt;/p&gt;  &lt;p&gt;It’s based around the idea of &lt;em&gt;agents&lt;/em&gt; in isolated &lt;em&gt;domains&lt;/em&gt; passing &lt;em&gt;messages&lt;/em&gt; to each other. On the new &lt;a href="http://blogs.msdn.com/maestroteam/" target="_blank"&gt;Maestro blog&lt;/a&gt; there’s an article giving &lt;a href="http://blogs.msdn.com/maestroteam/archive/2009/02/27/dataflow-programming-with-maestro.aspx" target="_blank"&gt;some examples&lt;/a&gt; of the funky syntax they’re introducing: &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;The &lt;strong&gt;forwarding operator,&lt;/strong&gt; ==&amp;gt; which is used to indicate that messages should be passed from a source to a target &lt;/li&gt;    &lt;li&gt;The &lt;strong&gt;broadcast operator,&lt;/strong&gt; –&amp;lt;&amp;lt; that broadcasts messages to a number of targets &lt;/li&gt;    &lt;li&gt;The &lt;strong&gt;multiplex operator,&lt;/strong&gt; &amp;gt;&amp;gt;- which combines messages from several sources before passing them to a single target &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Don’t get too excited just yet: Maestro is being described as an “incubation project”. That appears to mean that it’s a bit more than a research project, but not one that anybody has yet committed to shipping. I don’t think they’ve even released a version of this yet – I certainly can’t find a download.&lt;/p&gt;  &lt;p&gt;Once you’ve read the book, see &lt;a href="http://channel9.msdn.com/shows/Going+Deep/Maestro-A-Managed-Domain-Specific-Language-For-Concurrent-Programming/" target="_blank"&gt;the film&lt;/a&gt; on Channel 9.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Update (16/4/2009): Maestro has been renamed to Axum&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;As Mary-Jo &lt;a href="http://blogs.zdnet.com/microsoft/?p=2522" target="_blank"&gt;reported&lt;/a&gt;, Maestro has now been given the less musical code name of “Axum”. This is possibly due to a code-name clash with &lt;a href="http://www.microsoft.com/presspass/press/2005/may05/05-10maestropr.mspx" target="_blank"&gt;another Microsoft project&lt;/a&gt;, that one to do with business intelligence.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7577421612120825312-6332298200184677100?l=blog.functionalfun.net'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/zNq69XP91uWCPPllF8GgawQShRY/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/zNq69XP91uWCPPllF8GgawQShRY/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/zNq69XP91uWCPPllF8GgawQShRY/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/zNq69XP91uWCPPllF8GgawQShRY/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=3yu8ipy1ujU:igYHLi6PPpg:VYtfdMxc7SE"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=3yu8ipy1ujU:igYHLi6PPpg:VYtfdMxc7SE" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=3yu8ipy1ujU:igYHLi6PPpg:8U7eRf_NmwQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=8U7eRf_NmwQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=3yu8ipy1ujU:igYHLi6PPpg:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=3yu8ipy1ujU:igYHLi6PPpg:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=3yu8ipy1ujU:igYHLi6PPpg:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=3yu8ipy1ujU:igYHLi6PPpg:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=3yu8ipy1ujU:igYHLi6PPpg:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=3yu8ipy1ujU:igYHLi6PPpg:l6gmwiTKsz0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=3yu8ipy1ujU:igYHLi6PPpg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=3yu8ipy1ujU:igYHLi6PPpg:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=3yu8ipy1ujU:igYHLi6PPpg:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FunctionalFun/~4/3yu8ipy1ujU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.functionalfun.net/feeds/6332298200184677100/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.functionalfun.net/2009/02/maestro-new-net-language-for-parallel.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/6332298200184677100?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/6332298200184677100?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FunctionalFun/~3/3yu8ipy1ujU/maestro-new-net-language-for-parallel.html" title="Maestro: A new .Net language for parallel programming from Microsoft" /><author><name>Sam</name><uri>http://www.blogger.com/profile/01345100698738870730</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09416134415683403048" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.functionalfun.net/2009/02/maestro-new-net-language-for-parallel.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0QDQng-eCp7ImA9WxVWFkg.&quot;"><id>tag:blogger.com,1999:blog-7577421612120825312.post-2594023120899628289</id><published>2009-02-26T08:37:00.003Z</published><updated>2009-02-26T12:29:33.650Z</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-02-26T12:29:33.650Z</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Humour" /><category scheme="http://www.blogger.com/atom/ns#" term="Personal" /><title>Observing a bug in the dorsolateral prefrontal cortex</title><content type="html">&lt;p&gt;Just occasionally the &lt;a href="http://www.hopkinsmedicine.org/Press_releases/2008/02_26_08.html" target="_blank"&gt;self-censorship feature&lt;/a&gt; in my wife’s brain malfunctions, with amusing consequences: it kicks in the instant &lt;em&gt;after&lt;/em&gt; she has spoken, so that her next words are “don’t tell anybody I said that!”&lt;/p&gt;  &lt;p&gt;But I’m sure she won’t mind my sharing a few choice moments with you. &lt;/p&gt;  &lt;p&gt;First I should point out that my wife graduated with honours from one of the top medical schools in the UK, so there’s clearly nothing lacking in the rest of her brain. I speculate that Auto Update got turned off in this one area.&lt;/p&gt;  &lt;p&gt;The most recent example was when we were discussing a diagram of the solar system with our daughter. “So did the Greeks and Romans know what the planets are called when they named their gods?”, my wife asked me – then immediately put her hand over her mouth in embarrassment.&lt;/p&gt;  &lt;p&gt;But the funniest was a few years ago as we were driving through our neighbourhood at night, after there had been a power cut. The houses on either side of the road were eerily dark, and we were suddenly dazzled as another vehicle went past us in the opposite direction. My wife piped up,&lt;/p&gt;  &lt;p&gt;“So how come that car’s headlights are still working?”&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7577421612120825312-2594023120899628289?l=blog.functionalfun.net'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/5c5zq5iI0WBSRXPMB_LyvGh1Y30/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/5c5zq5iI0WBSRXPMB_LyvGh1Y30/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/5c5zq5iI0WBSRXPMB_LyvGh1Y30/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/5c5zq5iI0WBSRXPMB_LyvGh1Y30/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=OzfumUIjLFg:7Y-CUYmrPHQ:VYtfdMxc7SE"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=OzfumUIjLFg:7Y-CUYmrPHQ:VYtfdMxc7SE" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=OzfumUIjLFg:7Y-CUYmrPHQ:8U7eRf_NmwQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=8U7eRf_NmwQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=OzfumUIjLFg:7Y-CUYmrPHQ:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=OzfumUIjLFg:7Y-CUYmrPHQ:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=OzfumUIjLFg:7Y-CUYmrPHQ:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=OzfumUIjLFg:7Y-CUYmrPHQ:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=OzfumUIjLFg:7Y-CUYmrPHQ:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=OzfumUIjLFg:7Y-CUYmrPHQ:l6gmwiTKsz0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=OzfumUIjLFg:7Y-CUYmrPHQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FunctionalFun?a=OzfumUIjLFg:7Y-CUYmrPHQ:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FunctionalFun?i=OzfumUIjLFg:7Y-CUYmrPHQ:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FunctionalFun/~4/OzfumUIjLFg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.functionalfun.net/feeds/2594023120899628289/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.functionalfun.net/2009/02/observing-bug-in-dorsolateral.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/2594023120899628289?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7577421612120825312/posts/default/2594023120899628289?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FunctionalFun/~3/OzfumUIjLFg/observing-bug-in-dorsolateral.html" title="Observing a bug in the dorsolateral prefrontal cortex" /><author><name>Sam</name><uri>http://www.blogger.com/profile/01345100698738870730</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09416134415683403048" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://blog.functionalfun.net/2009/02/observing-bug-in-dorsolateral.html</feedburner:origLink></entry></feed>
