<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-3131102996085923653</id><updated>2011-07-07T21:47:29.839-07:00</updated><category term='ruby'/><category term='wcf'/><category term='apache'/><category term='linux'/><category term='linq'/><category term='javascript'/><category term='patterns'/><category term='gis'/><category term='wix'/><category term='nunit'/><category term='general'/><category term='offtopic'/><category term='oracle'/><category term='presentation'/><category term='c#'/><category term='jquery'/><category term='nettopologysuite'/><category term='arcobjects'/><category term='sql'/><category term='python'/><category term='asp.net'/><category term='testing'/><category term='automation'/><category term='topshelf'/><category term='nhibernate'/><category term='utility'/><category term='structuremap'/><title type='text'>Dylan Does Digits</title><subtitle type='html'>var posts = from i in ideas
            where i.interesting == true
            select i.content</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>50</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-3135461860214849223</id><published>2010-04-17T14:20:00.001-07:00</published><updated>2010-04-17T14:20:59.126-07:00</updated><title type='text'>Blog is moving</title><content type='html'>This blog has moved to&amp;nbsp;&lt;a href="http://digits.transatlantical.me/"&gt;http://digits.transatlantical.me&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3131102996085923653-3135461860214849223?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/3135461860214849223/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2010/04/blog-is-moving.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/3135461860214849223'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/3135461860214849223'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2010/04/blog-is-moving.html' title='Blog is moving'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-9132528279912524933</id><published>2010-04-10T10:05:00.000-07:00</published><updated>2010-04-10T10:05:03.019-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><category scheme='http://www.blogger.com/atom/ns#' term='oracle'/><title type='text'>Parameterized Query with LIKE using Oracle.DataAccess</title><content type='html'>If I have to figure this out yet again for the nth time, I'll get ticked off. So here is how to do a LIKE query in C# using an OracleParameter:&lt;pre&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.Linq;&lt;br /&gt;using System.Text;&lt;br /&gt;using Oracle.DataAccess;&lt;br /&gt;using Oracle.DataAccess.Client;&lt;br /&gt;using System.Data;&lt;br /&gt;&lt;br /&gt;namespace Oracle&lt;br /&gt;{&lt;br /&gt;    class Program&lt;br /&gt;    {&lt;br /&gt;        static void Main(string[] args)&lt;br /&gt;        {&lt;br /&gt;            const string searchTerm = "bd";&lt;br /&gt;            const string cs = @"Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=thehostname)(PORT=1521)))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=the.service.name)));User Id=user;Password=pass.word;";&lt;br /&gt;            const string sql = @"select rm_id, ref_fac_id || ' - ' || rm_num as name&lt;br /&gt;                        from asbestos.rooms&lt;br /&gt;                        where rownum &lt; 51&lt;br /&gt;                          and ref_fac_id is not null&lt;br /&gt;                          and( lower(ref_fac_id) like :q&lt;br /&gt;                            or lower(rm_num) like :q)&lt;br /&gt;                        order by rm_num asc";&lt;br /&gt;            var conn = new OracleConnection(cs);&lt;br /&gt;&lt;br /&gt;            var cmd = conn.CreateCommand();&lt;br /&gt;            cmd.CommandText = sql;&lt;br /&gt;            cmd.CommandType = CommandType.Text;&lt;br /&gt;            var param = cmd.CreateParameter();&lt;br /&gt;            param.DbType = DbType.String;&lt;br /&gt;            param.Direction = ParameterDirection.Input;&lt;br /&gt;            param.ParameterName = ":q";&lt;br /&gt;            param.Value = string.Format("{0}{1}{0}", "%", searchTerm.ToLower());&lt;br /&gt;            cmd.Parameters.Add(param);&lt;br /&gt;            conn.Open();&lt;br /&gt;&lt;br /&gt;            using (var reader = cmd.ExecuteReader(CommandBehavior.CloseConnection))&lt;br /&gt;            {&lt;br /&gt;                while (reader.Read())&lt;br /&gt;                {&lt;br /&gt;                    Console.WriteLine(reader.GetString(1));&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            Console.Read();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3131102996085923653-9132528279912524933?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/9132528279912524933/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2010/04/parameterized-query-with-like-using.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/9132528279912524933'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/9132528279912524933'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2010/04/parameterized-query-with-like-using.html' title='Parameterized Query with LIKE using Oracle.DataAccess'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-3744074689130410453</id><published>2010-03-26T13:29:00.000-07:00</published><updated>2010-03-26T15:58:02.148-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><category scheme='http://www.blogger.com/atom/ns#' term='wcf'/><title type='text'>Port blocking in Windows 7 makes for unhappy WCF testing</title><content type='html'>&lt;p&gt;I typically do something like this when I'm testing a WCF service (using NUnit here):&lt;/p&gt;&lt;pre&gt;namespace Tests&lt;br /&gt;{&lt;br /&gt;    [TestFixture]&lt;br /&gt;    class When_running_as_hosted_service&lt;br /&gt;    {&lt;br /&gt;        private ServiceHost _host;&lt;br /&gt;        private IWhoKnowsService _client;&lt;br /&gt;&lt;br /&gt;        [SetUp]&lt;br /&gt;        public void Before_any_test()&lt;br /&gt;        {&lt;br /&gt;            // 1.&lt;br /&gt;            // Start a WCF service hosted in a generic ServiceHost&lt;br /&gt;            // This is exactly the same as hosting in IIS or a console app&lt;br /&gt;            const string port = "http://localhost:12345/";&lt;br /&gt;            var uri = new Uri(port);&lt;br /&gt;            _host = new ServiceHost(typeof(WebService), uri);&lt;br /&gt;            _host.AddServiceEndpoint(typeof(IWhoKnowsService), new WSHttpBinding(), uri);&lt;br /&gt;            _host.Open();&lt;br /&gt;            &lt;br /&gt;            // 2.&lt;br /&gt;            // Now dynamically build a client to that service.&lt;br /&gt;            // This is the same as 'Add Service Reference' but without all&lt;br /&gt;            // of the code generation&lt;br /&gt;            _client = new ChannelFactory&lt;IWhoKnowsService&gt;(new WSHttpBinding())&lt;br /&gt;                .CreateChannel(new EndpointAddress(port));&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [TearDown]&lt;br /&gt;        public void After_all_tests()&lt;br /&gt;        {&lt;br /&gt;            // Tear it down so that the TCP port is release correctly&lt;br /&gt;            _host.Close();&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [Test]&lt;br /&gt;        public void Can_get_a_list_of_descripts_for_a_skill_level() &lt;br /&gt;        {&lt;br /&gt;            var descriptions = _client.DescriptionsByLevel(SkillLevel.Padwan);&lt;br /&gt;            Assert.IsNotNull(descriptions);&lt;br /&gt;            Assert.Greater(descriptions.Length, 0);&lt;br /&gt;&lt;br /&gt;            foreach (var item in descriptions)&lt;br /&gt;            {&lt;br /&gt;                Console.WriteLine(item);&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;I've used this technique many, many times on Windows XP but I just made the switch to Windows 7 for development, having skipped Vista entirely. When trying to run that test I get this error back from the test runner:&lt;/p&gt;&lt;pre&gt;AddressAccessDeniedException: HTTP could not register URL http://+:12345/&lt;…&gt;.  Your process does not have access rights to this namespace&lt;/pre&gt;&lt;p&gt;That's not good. So I hit the Internet and found an &lt;a href="http://blogs.msdn.com/drnick/archive/2006/10/16/configuring-http-for-windows-vista.aspx"&gt;excellent post&lt;/a&gt; by &lt;a href="http://blogs.msdn.com/drnick/default.aspx"&gt;Nicholas Allen&lt;/a&gt; that set me straight. Basically Windows 7 really locks down your usage of TCP ports over HTTP. Using the trusty old &lt;code&gt;netsh&lt;/code&gt; command he shows how to open up the port of choice in one easy step:&lt;pre&gt;netsh http add urlacl url=http://+:12345/ user=dev2010\Dylan&lt;/pre&gt;&lt;p&gt;Problem solved! I reran the test in Visual Studio and got a pass.&lt;/p&gt;&lt;blockquote&gt;NOTE: You must be running your Command Prompt as an administrator in order for this to work. In other words, right click on Command Prompt in your Start Menu and choose the appropriate option.&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3131102996085923653-3744074689130410453?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/3744074689130410453/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2010/03/port-blocking-in-windows-7-makes-for.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/3744074689130410453'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/3744074689130410453'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2010/03/port-blocking-in-windows-7-makes-for.html' title='Port blocking in Windows 7 makes for unhappy WCF testing'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-2163473375859607811</id><published>2010-03-18T09:12:00.000-07:00</published><updated>2010-03-18T09:18:03.359-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>Ruby strings on Windows. Backlashes again!</title><content type='html'>&lt;p&gt;There are all kinds of &lt;a href="http://stackoverflow.com/questions/648156/backslashes-in-single-quoted-strings-vs-double-quoted-strings-in-ruby"&gt;discussions&lt;/a&gt; about how to correctly use single or double quoted strings in Ruby, especially where character escaping is concerned. I was faced with just such an issue today and thought I'd share my experience.&lt;/p&gt;&lt;p&gt;Basically I'm building a rake script to automate my .NET project setup. Part of that setup involves doing some search and replace is SQL scripts so that a developer can store some settings in a config file and have that populate variables in files. For example:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;YAML file &lt;code&gt;config.yml&lt;/code&gt; contains a setting called &lt;code&gt;production -&gt; db -&gt; backup_location&lt;/code&gt;. The text in the file is &lt;code&gt;"\\\\some\\unc\\path\\name"&lt;/code&gt;. You see how the backslashes in the Windows path are doubled up? That's to satisfy Ruby and it is in double quotes.&lt;/li&gt;&lt;li&gt;The rake script uses this value as a parameter to a method that I wrote that is heavily influenced (copied with simplification!) by the &lt;a href="http://github.com/derickbailey/Albacore"&gt;albacore&lt;/a&gt; project, which is a set of rake tasks geared towards .NET projects. The important lines of the script are these:&lt;pre&gt;replacements.each do |search,replace|&lt;br /&gt;    search_term = "%#{search}%"&lt;br /&gt;    template_data.gsub!search_term, replace&lt;br /&gt;end&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;My SQL file has this in it that should have various paths inserted:&lt;pre&gt;FROM  DISK = N'%backup_file%' WITH  FILE = 1&lt;br /&gt; , MOVE N'Cityworks_Production' TO N'%db_dir%\Cityworks_WCS.mdf'&lt;br /&gt; , MOVE N'Cityworks_Production_log' TO N'%db_dir%\Cityworks_WCS_1.ldf'&lt;br /&gt; , MOVE N'sysft_CityworksFtCat' TO N'%db_dir%\Cityworks_WCS_2.CityworksFtCat'&lt;br /&gt; , move N'ftrow_CityworksFtCat' to N'%db_dir%\CityworksFtCat.ndf'&lt;br /&gt;,  NOUNLOAD,  STATS = 10&lt;br /&gt;GO&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Unfortunately when I run the script using a UNC path rather than a typical &lt;code&gt;C:/something/or/other&lt;/code&gt; path I could never get two backslashes to appear at the start of the path. I tried (literally!) every combination I could think of: doubling up, adding an extra backslash, single quotes, double quotes, you name it. Along the way I wrote a little one liner that converts a string from Ruby path to a Windows path (&lt;code&gt;winpath = ruby_path.gsub('/','\\')&lt;/code&gt;) but still no joy. Then I searched some more online and finally found an answer: it wasn't my various &lt;code&gt;File.join&lt;/code&gt; or &lt;code&gt;File.expand_path&lt;/code&gt; calls that were the issue: it was the &lt;code&gt;gsub&lt;/code&gt; call itself that was the problem.&lt;/p&gt;&lt;p&gt;In fact the question was &lt;a href="http://redmine.ruby-lang.org/issues/show/1443"&gt;answered by Matz himself&lt;/a&gt; (inventor of the Ruby language). While my string with four backslashes actually did give me the right answer of two escaped backslashes, &lt;code&gt;gsub&lt;/code&gt; also assigns special meaning to backslashes. So get this - you need to &lt;em&gt;quadruple&lt;/em&gt; any backslash in a string if you are going to gsub it. Crazy but true. Here's what my fixed up code looks like now:&lt;/p&gt;&lt;pre&gt;replacements.each do |search,replace|&lt;br /&gt;    search_term = "%#{search}%"&lt;br /&gt;    template_data.gsub! &lt;strong&gt;(search_term) { replace } unless replace.nil?&lt;/strong&gt;&lt;br /&gt;end&lt;/pre&gt;&lt;p&gt;The trick is to use a block rather than tacking on the &lt;code&gt;replace&lt;/code&gt; as a parameter. In this way gsub offloads the whole string interpretation to the block rather than doing its funky thing with interpreting the backslashes inline. Boy, am I glad I got that figured out.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3131102996085923653-2163473375859607811?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/2163473375859607811/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2010/03/ruby-strings-on-windows-backlashes.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/2163473375859607811'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/2163473375859607811'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2010/03/ruby-strings-on-windows-backlashes.html' title='Ruby strings on Windows. Backlashes again!'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-8824124615155475641</id><published>2010-02-25T12:06:00.001-08:00</published><updated>2010-02-25T12:06:23.801-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='general'/><title type='text'>A little coding test</title><content type='html'>&lt;h3&gt;Do this without compiling...&lt;/h3&gt;&lt;p&gt;Someone recently asked me about some questions to give someone during an interview. The fun part is having the interviewee do the problem on a white board without an IDE to help them. Or having them do it in Visual Studio, Eclipse, or whatever IDE they typically use for their language of choice. Here is one such problem. It&amp;rsquo;s not very complicated but it does force the interviewee to think about assumptions being made:&lt;/p&gt;&lt;blockquote&gt; &lt;p&gt;Given a certain amount of money that you need, and a set of coin denominations, tell me the minimum number of coins of each denomination I need to have that amount of money.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Having heard the problem statement I tried the whiteboard version. Then I opened up Visual Studio and typed out the following. I waited until I typed  the whole thing before trying to build or run tests, just to keep myself honest about assumptions I was making.&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;STOP! Try to do this yourself without reading my approach. Not that I'm right, fast, wrong, or anything else, but see how you do first.&lt;/p&gt;&lt;hr /&gt;&lt;pre&gt;public class CoinCounter&lt;br /&gt;{&lt;br /&gt;  /// &amp;lt;summary&amp;gt;&lt;br /&gt;  /// Assumptions made:&lt;br /&gt;  /// 1. There's always a denomination of 1 unit&lt;br /&gt;  /// 2. There are no fractional units like the 1/2 pence in England&lt;br /&gt;  /// 3. The denominations are always in the same units (cents, not cents and dollars)&lt;br /&gt;  /// &amp;lt;/summary&amp;gt;&lt;br /&gt;  public static Dictionary&lt;int, int&gt; GetMinimumCoinsNeeded(int[] denominations, int targetValue)&lt;br /&gt;  {&lt;br /&gt;    var result = new Dictionary&lt;int, int&gt;();&lt;br /&gt;    &lt;br /&gt;    // Sort in descending order so we get the biggest denomination first&lt;br /&gt;    Array.Sort(denominations);&lt;br /&gt;    Array.Reverse(denominations);&lt;br /&gt;    int remaining = targetValue;&lt;br /&gt;    &lt;br /&gt;    foreach (int denomination in denominations)&lt;br /&gt;    {&lt;br /&gt;      // Turns out there's a Math.DivRem function that gets both the&lt;br /&gt;      // coins and remaining value in one go.&lt;br /&gt;      int coins = remaining / denomination;&lt;br /&gt;      &lt;br /&gt;      // Forgot to add this first time through - don't need to&lt;br /&gt;      // do the rest if there aren't any coins&lt;br /&gt;      if (coins == 0) &lt;br /&gt;        continue;&lt;br /&gt;      &lt;br /&gt;      // Got this backwards first time - denomination % targetValue&lt;br /&gt;      remaining = targetValue % denomination;&lt;br /&gt;      result.Add(denomination, coins);&lt;br /&gt;      Console.WriteLine("Adding {0} coins of denomination {1} leaving {2} to work with...",&lt;br /&gt;            coins, denomination, remaining);&lt;br /&gt;      &lt;br /&gt;      if (remaining == 0)&lt;br /&gt;        break;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    return result;&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;h3&gt;And see if it works when you finally build it&lt;/h3&gt;&lt;p&gt;When I saw this problem I ended up with a solution that resembles the one above. I did make some goofy mistakes that involved some wiping out and re-&amp;ldquo;coding&amp;rdquo; on the whiteboard. For example, I'd just been using Excel to do some modulus work and actually wrote in the Excel &lt;code&gt;Mod&lt;/code&gt; function rather than the C# modulus (&lt;code&gt;%&lt;/code&gt;) built in function. Embarassing! The other things I found when I actually tried to compile then run the code are listed in C# comments. For example, I got the order of the two parameters in the &lt;code&gt;%&lt;/code&gt; call backwards. Here is the final part where I report the number of different coins to use:&lt;/p&gt;&lt;pre&gt;var result = CoinCounter.GetMinimumCoinsNeeded(new[] { 2, 1, 100, 500, 10, 25 }, 2341);&lt;br /&gt;&lt;br /&gt;foreach (var item in result)&lt;br /&gt;{&lt;br /&gt; Console.WriteLine("Denomination: {0}, Coins: {1}", item.Key, item.Value);&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;Which returns this output:&lt;/p&gt;&lt;pre&gt;Denomination: 500, Coins: 4&lt;br /&gt;Denomination: 100, Coins: 3&lt;br /&gt;Denomination: 25, Coins: 1&lt;br /&gt;Denomination: 10, Coins: 1&lt;br /&gt;Denomination: 1, Coins: 1&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Try it yourself. It&amp;rsquo;s a good test of your logic ability and knowledge of your core language and platform.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3131102996085923653-8824124615155475641?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/8824124615155475641/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2010/02/little-coding-test.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/8824124615155475641'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/8824124615155475641'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2010/02/little-coding-test.html' title='A little coding test'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-4180430218794100607</id><published>2010-02-22T20:29:00.000-08:00</published><updated>2010-02-22T20:29:57.110-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='apache'/><title type='text'>It only took me 3 hours to get Rails running on Ubuntu</title><content type='html'>&lt;p&gt;I wish! I've used Ruby (the .NET version IronRuby at least) for building a project, and tinkered with Rails in a non-serious way, but I find myself wanting to test something real for work these days. Well, it's a long shot, but I'm wondering what the cost in man hours would be to move our public Subversion subversion from a Windows 2003 VM to Ubuntu. The reason? I like VisualSVN Server for its ease of use and no brainer installation, but I need to get a decent web GUI for svn up and running. There's the PHP-based WebSVN project that presumably I can plug in to svn, but I honestly don't want to mess with co-hosting the private Apache server that VisualSVN uses on port 80 with a full blown Apache install...also on port 80...just for the PHP stuff.&lt;/p&gt;&lt;p&gt;Maybe that really isn't too big of a deal, but I also find myself wanting to try out the truly beautiful and useful svn GUI that is &lt;a href="http://warehouseapp.com/"&gt;Warehouse&lt;/a&gt;. It is a Ruby on Rails application, and that is the real impetus for trying Ubuntu and Apache: Rails is a bugger to get working correctly on Windows in anything other than play mode. I've tried mongrel packs (!), WebBrick (can't believe I actually did that), and other approaches and it just seems like I'm trying to force the Rails round peg into the Windows square hole. So on to Ubuntu.I've been using Sun's (Oracle's?) VirtualBox for a while now, ever since VMware completely hosed my laptop &lt;i&gt;and&lt;/i&gt; external USB drive with all my backups. I really like it because it just works and has great bridged networking support. What with all the crazy &lt;code&gt;eth0&lt;/code&gt; and other intuitive network adapter names on Linux, that out-of-the-box networking experiences is truly a blessing. So without further ado, here's a screenshot of my desktop about 10 minutes ago. I'm pretty pleased with progress thus far, even if most of it was trolling through online "HOW-TOs" and the phenomenal &lt;a href="http://www.tekpub.com/preview/linux"&gt;TekPub Linux for Softies&lt;/a&gt; screencast series (totally worth $14).&lt;/p&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_-FppOh0pKM8/S4NZUplY__I/AAAAAAAAEzE/Lhv8rd00nNI/s1600-h/2-22-2010+8-11-19+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="433" src="http://4.bp.blogspot.com/_-FppOh0pKM8/S4NZUplY__I/AAAAAAAAEzE/Lhv8rd00nNI/s640/2-22-2010+8-11-19+PM.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p&gt;I have to say, the &lt;code&gt;apt-get&lt;/code&gt; package manager for Ubuntu is truly amazing. I was floored when I just typed &lt;code&gt;sudo apt-get install apache2&lt;/code&gt; and it &lt;i&gt;just worked&lt;/i&gt;. Anyway, nothing useful to mention like how I actually got this far, but again, I'm pretty pleased with the end result: a scaffolded Rails app that actually serves up HTML. Woohoo!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3131102996085923653-4180430218794100607?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/4180430218794100607/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2010/02/it-only-took-me-3-hours-to-get-rails.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/4180430218794100607'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/4180430218794100607'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2010/02/it-only-took-me-3-hours-to-get-rails.html' title='It only took me 3 hours to get Rails running on Ubuntu'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_-FppOh0pKM8/S4NZUplY__I/AAAAAAAAEzE/Lhv8rd00nNI/s72-c/2-22-2010+8-11-19+PM.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-3997731051011886730</id><published>2010-02-22T11:08:00.001-08:00</published><updated>2010-02-22T11:08:19.617-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='oracle'/><title type='text'>Oracle Spatial SIG group</title><content type='html'>&lt;p&gt;I just finished setting up a new place on the web for the Independent Oracle User Group (IOUG) Oracle Spatial Special Interest Group (SIG). That&amp;rsquo;s a mouthful so luckily we abbreviate it to Spatial SIG and still know what we are referring to. Anyway, if you are interesting in Oracle Spatial technology then head on over to &lt;a href="http://groups.google.com/group/oracle-spatial-sig"&gt;the new group site&lt;/a&gt; and take a look at membership options, our charter, and the newly relaunched discussion list. Okay, so the discussion list has one post in it so far (from yours truly) but it will get more content as the days and weeks pass.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3131102996085923653-3997731051011886730?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/3997731051011886730/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2010/02/oracle-spatial-sig-group.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/3997731051011886730'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/3997731051011886730'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2010/02/oracle-spatial-sig-group.html' title='Oracle Spatial SIG group'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-3871471038492316854</id><published>2010-02-09T19:31:00.000-08:00</published><updated>2010-02-09T19:31:25.251-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='presentation'/><title type='text'>Lessons learned on a project...time to 'fess up</title><content type='html'>&lt;p&gt;Here's an internal presentation I gave at one of our &amp;lsquo;DevCasts&amp;rsquo; a few months back. I shared my successes and failures with the team in return for a great discussion on effective use of tooling, when is too much design, and some virtual back slapping. Nothing earth shattering but I learned a lot...meaning it hurt sometimes but felt good at the end of the project!&lt;/p&gt;&lt;div style="width:425px;text-align:left" id="__ss_3119060"&gt;&lt;a style="font:14px Helvetica,Arial,Sans-serif;display:block;margin:12px 0 3px 0;text-decoration:underline;" href="http://www.slideshare.net/dvhthomas/dev-cast-lessons-from-a-complex-application" title="Dev Cast - Lessons from a Complex Application"&gt;Dev Cast - Lessons from a Complex Application&lt;/a&gt;&lt;object style="margin:0px" width="425" height="355"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=devcast-structuringanapplication-100209212444-phpapp01&amp;stripped_title=dev-cast-lessons-from-a-complex-application" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=devcast-structuringanapplication-100209212444-phpapp01&amp;stripped_title=dev-cast-lessons-from-a-complex-application" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div style="font-size:11px;font-family:tahoma,arial;height:26px;padding-top:2px;"&gt;View more &lt;a style="text-decoration:underline;" href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a style="text-decoration:underline;" href="http://www.slideshare.net/dvhthomas"&gt;Dylan Thomas&lt;/a&gt;.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3131102996085923653-3871471038492316854?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/3871471038492316854/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2010/02/lessons-learned-on-projecttime-to-fess.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/3871471038492316854'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/3871471038492316854'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2010/02/lessons-learned-on-projecttime-to-fess.html' title='Lessons learned on a project...time to &apos;fess up'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-3686282251032958385</id><published>2010-02-09T16:32:00.000-08:00</published><updated>2010-02-09T16:43:58.847-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='utility'/><title type='text'>Markdown, Pandoc, Love</title><content type='html'>&lt;p&gt;I'm in the middle of writing a lengthly software requirements spec this week. It's actually been fun to go through the process again on a fresh project with a clean slate. The requirements gathering meetings were great: business leader, sales people, and developers all in one room and surprisingly united in their goals. I used the usual tools of the trade—like &lt;a href="http://freemind.sourceforge.net/wiki/index.php/Main_Page"&gt;FreeMind&lt;/a&gt; and &lt;a href="http://code.google.com/p/unable/"&gt;Unable&lt;/a&gt; (a clone of a great little note taking application called Notable)—and was able to get a lot of the requirements and user story details knocked out on site.&lt;/p&gt;&lt;p&gt;Then I was sitting back at the office wondering how to keep all of my SRS edits in version control and hit upon the idea of using HTML rather than Word. No good reason other than wanting to keep my changesets small. I'm very comfortable with HTML and can whip out a mean CSS/HTML combo in no time flat. The beauty of it all, of course, is that I can just &lt;em&gt;write&lt;/em&gt; what I want without fussing over headers, page numbers, indenting bullets the right amount, and all that guff. I like a good looking document as much as the next guy but frankly I just needed to focus on getting the requirements done, not worrying about the font color of my headings.&lt;/p&gt;&lt;h4&gt;Enter Markdown&lt;/h4&gt;&lt;p&gt;Being no stranger to sites like &lt;a href="http://www.stackoverflow.com/"&gt;Stack Overflow&lt;/a&gt; I know that people can write pretty complex stuff using HTML. But also that it's a total drag when again, all I really need is the write text with some minimal markup. So if I want to highlight something I might type &lt;code&gt;this is *important* stuff&lt;/code&gt; and I might want to create a bulleted list like so:&lt;/p&gt;&lt;pre&gt;* item one&lt;br /&gt;* item two&lt;br /&gt;* and something else&lt;/pre&gt;&lt;p&gt;This is pretty much how I write notes anyway, and it turns out it's very, very close to how a simple 'HTML lite' syntax called &lt;a href="http://daringfireball.net/projects/markdown/"&gt;Markdown&lt;/a&gt; does things. Essentially is a dead simple syntax that can be transformed into HTML by any number of tools. So I did a little test. I started to write my SRS in Markdown format using a text editor rather than Word, all the while committing my changes to Subversion. It was actually pretty nice and I did indeed focus on writing instead of formatting. But then what? I've got a text file in some goofy format that only a programmer could love (ahem! guilty as charged!!!). I needed to deliver something usable to my client like a web page. Here's what a typical section looks like:&lt;p /&gt;&lt;pre&gt;#### Trademarks&lt;br /&gt;All brand names and product names are trademarks or registered trademarks of their respective companies&lt;br /&gt;&lt;br /&gt;Software Requirements Purpose and Process&lt;br /&gt;-----------------------------------------&lt;br /&gt;&lt;br /&gt;A Software Requirement Specification--hereafter called an SRS--is an initial attempt to describe the functionality of a custom software product or custom system. It can be likened to the blueprint for building a new house (or perhaps remodeling an existing house). Just as an architect guides a homeowner through their needs for the new house, so Woolpert technical staff guide clients though the requirements process. This implies two very important points that the client project management team and stakeholders should remember through the software requirements process:&lt;br /&gt;&lt;br /&gt;* *Continuous client involvement* is crucial to success. A homeowner generally does not sign off on architectural plans early on and then just hope that the architect understood perfectly your meaning. Woolpert technical staff are highly skilled, but they cannot possibly know all the needs or business processes of the clients as well as they do.&lt;br /&gt;* *Requirements are a moving target*, not a set of mandates that are set in stone. To be sure, some requirements are so central to the project that they are unlikely to change. However, changing requirements...&lt;/pre&gt;&lt;p&gt;Ignore the actual content for a second, and focus on the simple rules that Markdown uses. If I want a heading I underline the text. If I want bullets I put an asterisk as the first character and leave some white space around the 'list'. If I want a highlight (&amp;lt;em&amp;gt; in HTML) I put a couple of asterisks around the text. Simple. To be sure there are complicated parts but at that point I just drop in the HTML, e.g., a &lt;code&gt;div&lt;/code&gt; is just a &lt;code&gt;div&lt;/code&gt;.&lt;/p&gt;&lt;h4&gt;Enter Pandoc&lt;/h4&gt;&lt;p&gt;In the 'Holy Cow! How did he &lt;em&gt;do&lt;/em&gt; that?' category I found a wonderful little program called &lt;a href="http://johnmacfarlane.net/pandoc/"&gt;Pandoc&lt;/a&gt; written in Haskell (?!) by an associate professor of philosophy from the University of California at Berkeley (!!!!???!?!). Not exactly a normal, run of the mill combination there, but Pandoc is a beautiful little program. It essentially does one thing, and does it exceptionally well: it takes one or more Markdown text files and spits out HTML or PDF (or DocBook and a few other formats). So in order to turn my &lt;code&gt;srs.markdown&lt;/code&gt; text file and various screenshots in to an HTML page complete this those hyperlink-thingies, I just double-click the batch file I wrote and in less than a second I've got an excellent SRS document in HTML format that my client can open on any computer, share with anyone on the team, and click around in. From my script you can see that I'm including some CSS stylesheets, I'm asking for HTML out, and I've overridden a default HTML template because I needed to add some autogenerated stuff to the HTML HEAD section. Oh, and I also wanted it to generate a hyperlink table of contents for me based upon my H tags. Short and sweet.&lt;/p&gt;&lt;pre&gt;pandoc -o srs.html&lt;br /&gt;  -c "assets/css/blueprint/print.css"&lt;br /&gt;  -c "assets/css/blueprint/screen.css"&lt;br /&gt;  -c "assets/css/woolpert.css"&lt;br /&gt;  -w html srs.markdown&lt;br /&gt;  --template html.template&lt;br /&gt;  --toc&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;I wish I could show you some of the output but I'm under a non-disclosure agreement. But I promise, it's really...neat. Not to mention, when I've made changes, my client simply gets the latest from my employer's public svn repository, double-clicks the same batch file, and gets the very latest docs. [Smile]&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3131102996085923653-3686282251032958385?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/3686282251032958385/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2010/02/markdown-pandoc-love.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/3686282251032958385'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/3686282251032958385'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2010/02/markdown-pandoc-love.html' title='Markdown, Pandoc, Love'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-2612017124417790224</id><published>2010-02-02T20:47:00.000-08:00</published><updated>2010-02-02T20:47:30.726-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='offtopic'/><title type='text'>Whew!</title><content type='html'>&lt;p&gt;Holy tamales, what a day! I just wrapped up a marathon session getting a new "product" ready for a demo on the east coast (yes, the one that's not the West Coast). I spent all of yesterday struggling with 3rd party vendor software and finally deciding that it sucked and I can do it better myself. So I ripped that stuff out, wrote some handy dandy SQL, and had a WAAAAAAY faster solution by 7:00am this morning.&lt;/p&gt;&lt;p&gt;I fed Lyra and reunited her with her pacifier to grant us some peace and quiet for an additional 30 minutes, and managed to knock out some other bugs that had be...well, bugging me. All before 8:00am :-) And a few hours later it's looking really spiffy. OK, so actually it's not that exciting to look at, just a couple of ASP.NET MVC sites with dead simple controllers. But man, oh man, is the code behind it all sweet. We've got messages, we've got reliability, we've got factories, we've got...whatever: it's freaking cool because it took me ages and the prospective client is going to be very excited when I show them a web page with their logo on it.&lt;/p&gt;&lt;p&gt;The real bottom line is that I can actually look forward to my long flight tomorrow as a time for tweaking and tinkering and polishing the demo rather than sweating my 'nads off while trying to just get the code working. “I love it when a plan comes together”&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3131102996085923653-2612017124417790224?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/2612017124417790224/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2010/02/whew.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/2612017124417790224'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/2612017124417790224'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2010/02/whew.html' title='Whew!'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-1261424622966643729</id><published>2010-02-02T07:39:00.000-08:00</published><updated>2010-02-02T07:39:50.055-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><category scheme='http://www.blogger.com/atom/ns#' term='gis'/><title type='text'>Poor man's spatial query against ArcSDE</title><content type='html'>&lt;p&gt;I pretty much forget this every single time that I need to do a quick minimum bounding extent (MBE) or 'bounding box' query in ArcSDE. The ArcObjects alternative is just too painful to deal with when you simply need the extent of a feature, and SQL does the trick.&lt;p&gt;&lt;pre&gt;use sde_database&lt;br /&gt;go&lt;br /&gt;declare @meter nvarchar(20)&lt;br /&gt;set @meter='MN13'&lt;br /&gt;&lt;br /&gt;select layer_id from sde.SDE_layers where [owner] = 'GIS'&lt;br /&gt;  and table_name='WMETER'&lt;br /&gt;&lt;br /&gt;-- Answer is 155, and this is the table name for the next query&lt;br /&gt;-- Notice the f155 here...&lt;br /&gt;&lt;br /&gt;select b.OBJECTID, f.eminx,f.eminy from gis.f155 f&lt;br /&gt;inner join gis.WMETER b&lt;br /&gt; on f.fid=b.Shape&lt;br /&gt;where b.SerialNumber = @meter;&lt;/pre&gt;&lt;p&gt;Like I said, stupid simple but I still have to &lt;a href="http://webhelp.esri.com/arcgisdesktop/9.3/index.cfm?TopicName=Feature_classes_in_a_geodatabase_in_SQL_Server"&gt;look it up every darn time&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/3131102996085923653-1261424622966643729?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/1261424622966643729/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2010/02/poor-mans-spatial-query-against-arcsde.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/1261424622966643729'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/1261424622966643729'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2010/02/poor-mans-spatial-query-against-arcsde.html' title='Poor man&apos;s spatial query against ArcSDE'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-6102734000599224562</id><published>2010-01-30T08:24:00.000-08:00</published><updated>2010-01-30T08:24:58.226-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='general'/><title type='text'>There are many ways to skin a cat</title><content type='html'>&lt;p&gt;A colleague just sent me this link. It's pretty funny on one hand since I can see myself in a few of the samples (like "Enterprise Developer" when I was doing my one and only Java project early in 2009 - that was an XML-eye opener!). But the other aspect is that there are always multiple ways to achieve the same goal in software development. That's why I like our internal peer review program: I get to see every conceivable approach and discuss the merits of each. Sure, some are smellier than others. But on the whole I like that fact that we can use our tool of choice is such a variety of ways. I just learned a bunch about Python by simply looking through the listing!&lt;/p&gt;&lt;script src="http://gist.github.com/289467.js?file=Evolution+of+a+Python+programmer.py"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3131102996085923653-6102734000599224562?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/6102734000599224562/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2010/01/there-are-many-ways-to-skin-cat.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/6102734000599224562'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/6102734000599224562'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2010/01/there-are-many-ways-to-skin-cat.html' title='There are many ways to skin a cat'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-4518751845430184055</id><published>2010-01-14T17:03:00.000-08:00</published><updated>2010-01-14T17:04:22.977-08:00</updated><title type='text'>Idiots Guide To UML Class Diagrams</title><content type='html'>I put this together and figured I'd share it. I always draw the wrong little diamond for aggregation vs. composition so maybe this will help me to use the right pen for the job next time! Please ignore the formatting. This is a cut'n'paste job from an HTML document that has very pretty styles in it. Blogger kind of hosed it.&lt;br /&gt;&lt;h1&gt;Basic &lt;abbr title="Unified Modeling Language"&gt;UML&lt;/abbr&gt; for Class Design&lt;/h1&gt;&lt;hr /&gt;&lt;h2&gt;Introduction&lt;/h2&gt;Unified Modeling Language (UML) is a graphical notation covering a wide variety of steps in software and system design. One of the core uses of UML is to design object oriented systems using classes, interfaces, relationships, and other simple graphical elements. The purpose of this document is to describe the most common elements of UML diagrams geared towards class design.&lt;br /&gt;All diagrams were created using the &lt;a href="http://yuml.me/" target="_blank" title="yUML"&gt;yUML&lt;/a&gt; website.&lt;br /&gt;&lt;h2&gt;The Elements&lt;/h2&gt;&lt;h3&gt;A Class&lt;/h3&gt;Just the class - no properties or other information&lt;br /&gt;&lt;img src="http://yuml.me/diagram/scruffy/class/[User]" /&gt; &lt;br /&gt;A class with details. The name is at the top. The public fields (or properties) come next. They have a plus sign if they are public and a minus sign if they are private. Finally come the methods, again marked public or private with signs.&lt;br /&gt;&lt;img src="http://yuml.me/diagram/scruffy/class/[User%7C+Forename+;Surname;+HashedPassword;-Salt%7C+Login%28%29;+Logout%28%29]" /&gt; &lt;br /&gt;&lt;h3&gt;An Interface&lt;/h3&gt;Just the name - no other contract details&lt;br /&gt;&lt;img src="http://yuml.me/diagram/scruffy/class/[%3C%3CITask%3E%3E]" /&gt; &lt;br /&gt;With some details&lt;br /&gt;&lt;img src="http://yuml.me/diagram/scruffy/class/[%3C%3CITask%3E%3E;Execute%28%29]" /&gt;  &lt;br /&gt;&lt;h2&gt;Relationships&lt;/h2&gt;There are a few different kinds of relationships and deciding which one to use can be a bit confusing at first because it depends upon the &lt;i&gt;intent&lt;/i&gt; of the relationship. Simple associations sort of ignore the two main types of associtions and can be used for higher level UML diagrams. But being more specific is important as the design evolves and so understanding the difference between aggregation and composition is key. It really comes down to ownership and object lifecycle&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;br /&gt;&lt;b&gt;Aggregation&lt;/b&gt;—This is known as a &lt;q&gt;has a&lt;/q&gt; relationship because the containing object &lt;q&gt;has a&lt;/q&gt; member object. But here is the critical part: The member object can survive or exist without the enclosing or containing class, so it can have a meaning beyond the lifetime of the enclosing object.&lt;br /&gt;&lt;i&gt;Example: A room has a table and the table can exist without the room.&lt;/i&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;br /&gt;&lt;b&gt;Composition&lt;/b&gt;—This is known as a &lt;q&gt;is a part of&lt;/q&gt; or &lt;q&gt;is a&lt;/q&gt; relationship because the member object is part of the containing class and cannot existing or survive outside the context of the containing class. This also means that the lifetime of the member object ends with the lifetime of the enclosing object.&lt;br /&gt;&lt;i&gt;Example: The IT Department is part of the Company. The IT Department cannot exist without the Company and has no meaning after the lifetime of the Company.&lt;/i&gt;&lt;br /&gt; &lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Simple Association&lt;/h3&gt;Customers &lt;i&gt;have a&lt;/i&gt; Billing Address&lt;br /&gt;&lt;img src="http://yuml.me/diagram/scruffy/class/[Customer]-%3E[Billing%20Address]" /&gt;  &lt;br /&gt;The relationship between a Customer and and their Orders is described by the action &lt;q&gt;orders&lt;/q&gt;. So it read &lt;i&gt;a Customer orders an Order&lt;/i&gt;.&lt;br /&gt;&lt;img src="http://yuml.me/diagram/scruffy/class/[Customer]1-orders%200..*%3E[Order]" /&gt;  &lt;br /&gt;&lt;h3&gt;Cardinality&lt;/h3&gt;A Customer can have zero or more Addresses. An Address must have exactly one Customer. Notice how the numbers are positioned on the line: the customer fact (zero or more) is written next to the Address class.&lt;br /&gt;&lt;img src="http://yuml.me/diagram/scruffy/class/[Customer]1-0..*[Address]" /&gt;  &lt;br /&gt;&lt;h3&gt;Directionality&lt;/h3&gt;An Order has an Address called &lt;code&gt;billing&lt;/code&gt; and an Address called &lt;code&gt;shipping&lt;/code&gt;. This does not say anything about the Address-to-Order relationship.&lt;br /&gt;&lt;img src="http://yuml.me/diagram/scruffy/class/[Order]-billing%20%3E[Address],%20[Order]-shipping%20%3E[Address]" /&gt;  &lt;br /&gt;&lt;h3&gt;Aggregation&lt;/h3&gt;A Company has exactly one Location. A Location has a Point.&lt;br /&gt;&lt;img src="http://yuml.me/diagram/scruffy/class/[Company]%3C%3E-1%3E[Location],%20[Location]+-%3E[Point]" /&gt;  &lt;br /&gt;&lt;h3&gt;Composition&lt;/h3&gt;The Company has exactly one Location. The Location does not exist outside of the context of the Company.&lt;br /&gt;&lt;img src="http://yuml.me/diagram/scruffy/class/[Company]++-1%3E[Location]" /&gt;  &lt;br /&gt;&lt;h2&gt;Other Dependencies&lt;/h2&gt;&lt;h3&gt;Inheritance&lt;/h3&gt;Both the Contract and Salaried classes inherit from the Wages class.&lt;br /&gt;&lt;img src="http://yuml.me/diagram/scruffy/class/[Wages]%5E-[Salaried],%20[Wages]%5E-[Contractor]" /&gt;  &lt;br /&gt;The NightlyBillingTask class inherits (implements) the ITask interface&lt;br /&gt;&lt;img src="http://yuml.me/diagram/scruffy/class/[%3C%3CITask%3E%3E]%5E-.-[NightlyBillingTask]" /&gt;  &lt;br /&gt;&lt;h3&gt;Dependents On&lt;/h3&gt;The HttpContext class is dependent upon the Response class. The relationship reads as &lt;q&gt;the HttpContext class &lt;b&gt;uses&lt;/b&gt; the Response class&lt;/q&gt;. There is no &lt;q&gt;has a&lt;/q&gt; or &lt;q&gt;is part of a&lt;/q&gt; Response implied here. It is just plain usage.&lt;br /&gt;&lt;img src="http://yuml.me/diagram/scruffy/class/[HttpContext]uses%20-.-%3E[Response]" /&gt;  &lt;br /&gt;&lt;h2&gt;A Complete Example&lt;/h2&gt;Here it all comes together with some extra annotations in the form of notes.&lt;br /&gt;&lt;img src="http://yuml.me/diagram/scruffy/class/[note:%20The%20Customer%20has%20orders.%20Each%20order%20has%20exactly%20one%20delivery%20methods%20which%20could%20be%20one%20of%20two%20types%7Bbg:cornsilk%7D],[Customer]%3C%3E1-orders%200..*%3E[Order],%20[Order]++*-*%3E[LineItem],%20[Order]-1%3E[DeliveryMethod],%20[Order]*-*%3E[Product],%20[Category]%3C-%3E[Product],%20[DeliveryMethod]%5E[National],%20[DeliveryMethod]%5E[International]" /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3131102996085923653-4518751845430184055?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/4518751845430184055/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2010/01/idiots-guide-to-uml-class-diagrams.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/4518751845430184055'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/4518751845430184055'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2010/01/idiots-guide-to-uml-class-diagrams.html' title='Idiots Guide To UML Class Diagrams'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-6540825163491915274</id><published>2010-01-13T20:58:00.001-08:00</published><updated>2010-02-09T19:32:45.534-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='presentation'/><title type='text'>Dev Cast Dependency Injection</title><content type='html'>&lt;p&gt;This is pretty basic stuff, but that's sort of the point. I'm giving this presentation before a bunch of code samples at my company tomorrow. We call these ad hoc "share some ideas" meetings DevCasts (props to Joe for the name).&lt;/p&gt;&lt;div style="width:425px;text-align:left" id="__ss_2910479"&gt;&lt;a style="font:14px Helvetica,Arial,Sans-serif;display:block;margin:12px 0 3px 0;text-decoration:underline;" href="http://www.slideshare.net/dvhthomas/dev-cast-dependency-injection" title="Dev Cast Dependency Injection"&gt;Dev Cast Dependency Injection&lt;/a&gt;&lt;object style="margin:0px" width="425" height="355"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=devcastdependencyinjection-100113225409-phpapp02&amp;stripped_title=dev-cast-dependency-injection" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=devcastdependencyinjection-100113225409-phpapp02&amp;stripped_title=dev-cast-dependency-injection" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div style="font-size:11px;font-family:tahoma,arial;height:26px;padding-top:2px;"&gt;View more &lt;a style="text-decoration:underline;" href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a style="text-decoration:underline;" href="http://www.slideshare.net/dvhthomas"&gt;Dylan Thomas&lt;/a&gt;.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3131102996085923653-6540825163491915274?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/6540825163491915274/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2010/01/dev-cast-dependency-injection.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/6540825163491915274'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/6540825163491915274'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2010/01/dev-cast-dependency-injection.html' title='Dev Cast Dependency Injection'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-8714528364558559580</id><published>2010-01-05T20:31:00.000-08:00</published><updated>2010-01-05T20:31:26.689-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><title type='text'>Running a bunch of SQL scripts in C#</title><content type='html'>&lt;p&gt;Here is how I did it. Read in any script called &lt;code&gt;*.sql&lt;/code&gt; from a directory that does not have the word 'test' somewhere in it, then use the &lt;code&gt;Microsoft.SqlServer.Management.Common&lt;/code&gt; and &lt;code&gt;Microsoft.SqlServer.Management.Smo&lt;/code&gt; namespaces for the following:&lt;pre&gt;public bool RestoreFieldDatabaseFromBackup(string connectionString)&lt;br /&gt;{&lt;br /&gt; List&lt;string&gt; scripts = this._sqlDirectory.GetFiles("*.sql", SearchOption.AllDirectories)&lt;br /&gt;  .Where(s =&gt; !s.Name.Contains("test"))&lt;br /&gt;  .Select(s =&gt; s.FullName).ToList();&lt;br /&gt;&lt;br /&gt; if (scripts.Count() == 0) return false;&lt;br /&gt;&lt;br /&gt; var connection = new SqlConnection(connectionString);&lt;br /&gt;&lt;br /&gt; try&lt;br /&gt; {&lt;br /&gt;  for (int i = 0; i &lt; scripts.Count; i++)&lt;br /&gt;  {&lt;br /&gt;   using (var reader = new StreamReader(scripts[i]))&lt;br /&gt;   {&lt;br /&gt;    var server = new Server(new ServerConnection(connection));&lt;br /&gt;    var db = new Database(server, connection.Database);&lt;br /&gt;    string scriptText = reader.ReadToEnd();&lt;br /&gt;    Log.For(this).Debug("Running: " + scripts[i]);&lt;br /&gt;    db.ExecuteNonQuery(scriptText);&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt; catch (Exception ex)&lt;br /&gt; {&lt;br /&gt;  Log.For(this).Error(ex);&lt;br /&gt;  return false;&lt;br /&gt; }&lt;br /&gt; return true;&lt;br /&gt;}&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3131102996085923653-8714528364558559580?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/8714528364558559580/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2010/01/running-bunch-of-sql-scripts-in-c.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/8714528364558559580'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/8714528364558559580'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2010/01/running-bunch-of-sql-scripts-in-c.html' title='Running a bunch of SQL scripts in C#'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-8327463900406214023</id><published>2009-12-24T10:41:00.000-08:00</published><updated>2009-12-24T10:41:55.557-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linq'/><title type='text'>LINQ to objects: gettting the SQL version into C#</title><content type='html'>&lt;p&gt;In my last post I described a SQL query that grouped records by an ID (non unique obviously otherwise what is the point of grouping in the first place?), and then selected only the most recently created record from each group. I have been struggling with the LINQ query to do that same thing in C# and finally hit upon an answer. Not &lt;em&gt;the&lt;/em&gt; answer maybe, but it works so I&amp;rsquo;ll call in 'an' answer&lt;/p&gt;&lt;pre&gt;void Main()&lt;br /&gt;{&lt;br /&gt; var list = new WorkorderStatusChangeEvent().Build();&lt;br /&gt; var ids = from w in list&lt;br /&gt;   group w by w.WorkorderID into g&lt;br /&gt;   let latestDate = g.Max(w =&gt; w.TimeOfEvent)&lt;br /&gt;   select g.Where(w =&gt; w.TimeOfEvent == latestDate)&lt;br /&gt;    .Select(w =&gt; w.Id).First();&lt;br /&gt; var results = list.Where(x =&gt; ids.Contains(x.Id));&lt;br /&gt; results.Dump();    &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class WorkorderStatusChangeEvent&lt;br /&gt;{&lt;br /&gt; public virtual Guid Id { get; set; }&lt;br /&gt; public virtual string WorkorderID { get; set; }&lt;br /&gt; public virtual string OldStatus { get; set; }&lt;br /&gt; public virtual string NewStatus { get; set; }&lt;br /&gt; public virtual DateTime TimeOfEvent { get; set; }&lt;br /&gt; &lt;br /&gt; public IList&lt;WorkorderStatusChangeEvent&gt; Build()&lt;br /&gt; {&lt;br /&gt;  var earliest = new WorkorderStatusChangeEvent&lt;br /&gt;     {&lt;br /&gt;     Id = Guid.NewGuid(),&lt;br /&gt;     OldStatus = string.Empty,&lt;br /&gt;     NewStatus = "NO",&lt;br /&gt;     TimeOfEvent = DateTime.UtcNow.Subtract(TimeSpan.FromSeconds(120)),&lt;br /&gt;     WorkorderID = "123"&lt;br /&gt;   };&lt;br /&gt;  var earlier = new WorkorderStatusChangeEvent&lt;br /&gt;       {&lt;br /&gt;        Id = Guid.NewGuid(),&lt;br /&gt;        OldStatus = "BLAH",&lt;br /&gt;        NewStatus = "NO",&lt;br /&gt;        TimeOfEvent = DateTime.UtcNow.Subtract(TimeSpan.FromSeconds(60)),&lt;br /&gt;        WorkorderID = "456"&lt;br /&gt;       };&lt;br /&gt;  var latest = new WorkorderStatusChangeEvent&lt;br /&gt;       {&lt;br /&gt;        Id = Guid.NewGuid(),&lt;br /&gt;        OldStatus = "BLAH",&lt;br /&gt;        NewStatus = "YES",&lt;br /&gt;        TimeOfEvent = DateTime.UtcNow,&lt;br /&gt;        WorkorderID = "456"&lt;br /&gt;       };&lt;br /&gt;  var anotherone = new WorkorderStatusChangeEvent&lt;br /&gt;       {&lt;br /&gt;        Id = Guid.NewGuid(),&lt;br /&gt;        OldStatus = "BLAH",&lt;br /&gt;        NewStatus = "NO",&lt;br /&gt;        TimeOfEvent = DateTime.UtcNow.Subtract(TimeSpan.FromSeconds(300)),&lt;br /&gt;        WorkorderID = "456"&lt;br /&gt;       };&lt;br /&gt;  IList&lt;WorkorderStatusChangeEvent&gt; list = new List&lt;WorkorderStatusChangeEvent&gt;();&lt;br /&gt;  list.Add(earliest);&lt;br /&gt;  list.Add(earlier);&lt;br /&gt;  list.Add(latest);&lt;br /&gt;  list.Add(anotherone);&lt;br /&gt;  &lt;br /&gt;  return list;&lt;br /&gt; }&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;Basically there are two parts. First getting the groupings by WorkorderID and extracting the PK of the object (Id) for the most recent record. This uses the &lt;c&gt;let&lt;/c&gt; statement. The second part is a simple &lt;c&gt;contains&lt;/c&gt; query that does the equivalent of a SQL &lt;c&gt;IN&lt;/c&gt; to pull only those records from &lt;c&gt;list&lt;/c&gt; whose Id is in the list of grouped/max date matches.&lt;/p&gt;&lt;p&gt;And by the way, I absolutely could not have ever figured this out without the great &lt;a href="http://www.linqpad.net"&gt;LINQPad&lt;/a&gt; tool by Joseph Albahari. It is free and yet absolutely priceless. Here are the results from the query as presented by the &lt;c&gt;Dump&lt;/c&gt; extension method that LINQPad provides:&lt;/p&gt;&lt;table id="t86"&gt;        &lt;tr&gt;          &lt;td class="typeheader" colspan="5"&gt;              &lt;span class="typeglyph" id="t86ud"&gt;5&lt;/span&gt;IEnumerable&amp;lt;WorkorderStatusChangeEvent&amp;gt; (2 items)          &lt;/td&gt;        &lt;/tr&gt;        &lt;tr&gt;          &lt;th title="System.Guid"&gt;Id&lt;/th&gt;          &lt;th title="System.String"&gt;WorkorderID&lt;/th&gt;          &lt;th title="System.String"&gt;OldStatus&lt;/th&gt;          &lt;th title="System.String"&gt;NewStatus&lt;/th&gt;          &lt;th title="System.DateTime"&gt;TimeOfEvent&lt;/th&gt;        &lt;/tr&gt;        &lt;tr&gt;          &lt;td&gt;            &lt;p&gt;8191ab38-e070-4fd0-a8ea-83a7090c16d6&lt;/p&gt;          &lt;/td&gt;          &lt;td&gt;            &lt;p&gt;123&lt;/p&gt;          &lt;/td&gt;          &lt;td&gt;            &lt;p&gt;&lt;/p&gt;          &lt;/td&gt;          &lt;td&gt;            &lt;p&gt;NO&lt;/p&gt;          &lt;/td&gt;          &lt;td&gt;            &lt;p&gt;12/24/2009 6:29:51 PM&lt;/p&gt;          &lt;/td&gt;        &lt;/tr&gt;        &lt;tr&gt;          &lt;td&gt;            &lt;p&gt;a5cee31a-643c-4642-b0f6-3c8f6e54cbfe&lt;/p&gt;          &lt;/td&gt;          &lt;td&gt;            &lt;p&gt;456&lt;/p&gt;          &lt;/td&gt;          &lt;td&gt;            &lt;p&gt;BLAH&lt;/p&gt;          &lt;/td&gt;          &lt;td&gt;            &lt;p&gt;YES&lt;/p&gt;          &lt;/td&gt;          &lt;td&gt;            &lt;p&gt;12/24/2009 6:31:51 PM&lt;/p&gt;          &lt;/td&gt;        &lt;/tr&gt;      &lt;/table&gt;&lt;p&gt;And finally, have a great holiday. I've promised not to do any more techie stuff until the New Year. Well, I'm not going to blog until the New Year anyway!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3131102996085923653-8327463900406214023?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/8327463900406214023/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/12/linq-to-objects-gettting-sql-version.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/8327463900406214023'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/8327463900406214023'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/12/linq-to-objects-gettting-sql-version.html' title='LINQ to objects: gettting the SQL version into C#'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-590374818091483097</id><published>2009-12-23T10:16:00.000-08:00</published><updated>2009-12-23T10:16:49.630-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><title type='text'>SQL: grouping by maximum date and ID</title><content type='html'>&lt;p&gt;Another reminder to myself. I have an audit table that is populated by a trigger on a table. I use this table to drive another process and that process involves finding the most recent addition to the table for a specific work order. So basically if a work order has it&amp;rsquo;s status changed multiple times&amp;mdash;which is perfectly valid&amp;mdash;I need to know the last change only. Here is what the source data looks like after changing status on a couple of work orders:&lt;/p&gt;&lt;table&gt; &lt;tr&gt;&lt;th&gt;Id&lt;/th&gt;&lt;th&gt;WorkorderId&lt;/th&gt;&lt;th&gt;OldStatus&lt;/th&gt;&lt;th&gt;NewStatus&lt;/th&gt;&lt;th&gt;TimeOfUpdate&lt;/th&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td&gt;F0FE4F81-4CEF-DE11-8442-001C23437026&lt;/td&gt;&lt;td&gt;10&lt;/td&gt;&lt;td&gt;null&lt;/td&gt;&lt;td&gt;CLOSED&lt;/td&gt;&lt;td&gt;2009-12-22 22:51:14.377&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td&gt;F1FE4F81-4CEF-DE11-8442-001C23437026&lt;/td&gt;&lt;td&gt;10&lt;/td&gt;&lt;td&gt;CLOSED&lt;/td&gt;&lt;td&gt;OPEN&lt;/td&gt;&lt;td&gt;2009-12-22 22:51:14.390&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td&gt;F2FE4F81-4CEF-DE11-8442-001C23437026&lt;/td&gt;&lt;td&gt;10&lt;/td&gt;&lt;td&gt;OPEN&lt;/td&gt;&lt;td&gt;CLOSED&lt;/td&gt;&lt;td&gt;2009-12-22 22:51:14.390&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td&gt;F3FE4F81-4CEF-DE11-8442-001C23437026&lt;/td&gt;&lt;td&gt;9&lt;/td&gt;&lt;td&gt;null&lt;/td&gt;&lt;td&gt;CLOSED&lt;/td&gt;&lt;td&gt;2009-12-22 22:51:14.390&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;p&gt;Because I created these by firing the trigger in a SQL script for testing the times for two of the records for work order 10 are identical. That&amp;rsquo;s OK; in fact I need to deal with this possibility in my application so I&amp;rsquo;m glad it happened that way. Anyway, here&amp;rsquo;s the SQL that I wrote to get the information that I need. Not rocket science but it is just one of those things that had me stumped for a while until it dawned on me that I needed an inner join rather than a subquery.&lt;/p&gt;&lt;pre&gt;select w.Id&lt;br /&gt; , w.NewStatus&lt;br /&gt; , w.OldStatus&lt;br /&gt; , w.TimeOfUpdate&lt;br /&gt; , w.WorkorderId&lt;br /&gt;from Test.WCS.WorkorderStatusChange w&lt;br /&gt; -- Inner join on the max date grouped by workorder id&lt;br /&gt; inner join (select w.WorkorderId as woi, MAX(w.TimeOfUpdate) as tou&lt;br /&gt;   from Test.WCS.WorkorderStatusChange w&lt;br /&gt;   group by w.WorkorderId) as t&lt;br /&gt;  on t.tou = w.TimeOfUpdate&lt;br /&gt;  and t.woi = w.WorkorderId&lt;/pre&gt;&lt;p&gt;And that gives me what I need. Again, notice that the two results for work order 10 are valid because both have the &lt;code&gt;MAX(TimeOfUpdate)&lt;/code&gt; value:&lt;/p&gt;&lt;table&gt; &lt;tr&gt;&lt;th&gt;Id&lt;/th&gt; &lt;th&gt;NewStatus&lt;/th&gt; &lt;th&gt;OldStatus&lt;/th&gt; &lt;th&gt;TimeOfUpdate&lt;/th&gt; &lt;th&gt;WorkorderId&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;F3FE4F81-4CEF-DE11-8442-001C23437026&lt;/td&gt; &lt;td&gt;CLOSED&lt;/td&gt; &lt;td&gt;null &lt;/td&gt;&lt;td&gt;2009-12-22 22:51:14.390&lt;/td&gt; &lt;td&gt;9&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;F1FE4F81-4CEF-DE11-8442-001C23437026&lt;/td&gt; &lt;td&gt;OPEN &lt;/td&gt;&lt;td&gt;CLOSED&lt;/td&gt; &lt;td&gt;2009-12-22 22:51:14.390&lt;/td&gt; &lt;td&gt;10&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;F2FE4F81-4CEF-DE11-8442-001C23437026&lt;/td&gt; &lt;td&gt;CLOSED&lt;/td&gt; &lt;td&gt;OPEN&lt;/td&gt; &lt;td&gt;2009-12-22 22:51:14.390&lt;/td&gt; &lt;td&gt;10&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;p&gt;Of course the real question on my mind now is how the heck to do that with HQL or the Criteria API in NHibernate? I&amp;rsquo;ve wrestled with it for some time now and have basically given up. I am going to grab the whole lot of data from SQL Server and use LINQ to objects to filter out what I need. This is acceptable in this particular case because I delete the rows in the status table once I have read them in; they are only there long enough for the application to add a message to a message queue using the information. Still, it&amp;rsquo;s bugging me that I cannot figure out the query in NHibernate.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3131102996085923653-590374818091483097?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/590374818091483097/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/12/sql-grouping-by-maximum-date-and-id.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/590374818091483097'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/590374818091483097'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/12/sql-grouping-by-maximum-date-and-id.html' title='SQL: grouping by maximum date and ID'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-3967755056372346460</id><published>2009-12-19T09:10:00.000-08:00</published><updated>2009-12-19T09:10:07.103-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='automation'/><category scheme='http://www.blogger.com/atom/ns#' term='utility'/><title type='text'>Building WSDLs from .NET assemblies</title><content type='html'>&lt;p&gt;More of a reminder to myself than anything else, here's a batch file that creates proxy classes that can talk to WCF services. The WCF service interfaces are defined in the Visual Studio project build output. Then it's a simple matter of using the &lt;code&gt;svcutil&lt;/code&gt; command line utility from the .NET SDK to go through the motions. This turns out to be a great way to automate the creation of WSDLs for non-.NET clients, and a good way to create proxy classes that you have a lot more control over than the &amp;ldquo;Add Service Reference&amp;rdquo; approach in Visual Studio.&lt;/p&gt;&lt;pre&gt;set outDir=..\build\wcs-wsdl&lt;br /&gt;set wsdlDir=..\lib\wcs-wsdl&lt;br /&gt;set svc="C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\svcutil.exe"&lt;br /&gt;set msbuild="C:\WINDOWS\Microsoft.NET\Framework\v3.5\msbuild.exe"&lt;br /&gt;&lt;br /&gt;rmdir /s /q %outDir%&lt;br /&gt;mkdir %outDir%&lt;br /&gt;&lt;br /&gt;%msbuild% ..\source\Woolpert.Cityworks.Services\Woolpert.Cityworks.Services.csproj&lt;br /&gt;%svc% ..\source\Woolpert.Cityworks.Services\bin\Debug\Woolpert.Cityworks.Services.dll&lt;br /&gt;%svc% *.xsd www.woolpert.com.wis.cityworks.wsdl /language:C# /out:%outDir%\CityworksClient.cs&lt;br /&gt;%svc% *.xsd www.woolpert.com.wis.security.wsdl /language:C# /out:%outDir%\SecurityClient.cs&lt;br /&gt;%svc% *.xsd www.woolpert.com.wis.spatial.wsdl /language:C# /out:%outDir%\SpatialClient.cs&lt;br /&gt;xcopy *.xsd %wsdlDir%\ /I /Y&lt;br /&gt;xcopy *.wsdl %wsdlDir%\ /I /Y&lt;br /&gt;xcopy *.config %wsdlDir%\ /I /Y&lt;br /&gt;del /q *.xsd&lt;br /&gt;del /q *.wsdl&lt;br /&gt;del /q *.config&lt;/pre&gt;&lt;p&gt;In my other projects that need access to clients I can then run a subset of this script and be all set for consuming the web services:&lt;/p&gt;&lt;pre&gt;set output=MyMiddleware.cs&lt;br /&gt;del %output%&lt;br /&gt;set svc="C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\svcutil.exe"&lt;br /&gt;%svc% *.wsdl *.xsd /language:C# /o:%output%&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3131102996085923653-3967755056372346460?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/3967755056372346460/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/12/building-wsdls-from-net-assemblies.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/3967755056372346460'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/3967755056372346460'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/12/building-wsdls-from-net-assemblies.html' title='Building WSDLs from .NET assemblies'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-5921945564339150866</id><published>2009-12-06T15:00:00.000-08:00</published><updated>2009-12-07T19:19:17.225-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='nhibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><title type='text'>NHibernate Events to the rescue</title><content type='html'>&lt;h4&gt;The Issue, in which Dylan gets bit in the ass by a legacy database&lt;/h4&gt;&lt;p&gt;I'm building some message-oriented-middleware (MOM?) for a 3&lt;sup&gt;rd&lt;/sup&gt; party vendor product. The database has evolved over many years and has all of the quirks that you might expect of such a system: primary keys that are implied but not made explicit with constraints, relationships that are implied but not explicit, columns that are not nullable in the business logic but are nullable in the tables, etc. I&amp;rsquo;m not knocking the vendor: I am keenly aware that keeping a multipurpose database absolutely clean of cruft is a tough challenge indeed. But it does make for some really tough integration points. My major challenge over the past week has been auditing. The vendor system makes very heavy use of &lt;abbr title="stored procedures"&gt;sprocs&lt;/abbr&gt; and embeds the creation of the audit trail in those sprocs rather than using what, to my mind, is the more obvious approach of triggers.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Walking through an example, let&amp;rsquo;s say that my MOM or some other end user creates a new workorder record. The steps go like this:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Call the sproc to add the workorder&amp;mdash;This itself calls a number of other sprocs with all kinds of logic in there based upon magic strings. Hairs standing up on the back of my neck!&lt;/li&gt;&lt;li&gt;Call the sproc to do the auditing&lt;ol&gt;&lt;li&gt;Get the name of the table you&amp;rsquo;re adding a record to. In this case it might be something like "WORKORDERS".&lt;/li&gt;&lt;li&gt;Query a table that has a listing of specific columns in tables to keep an audit trail on. So the query might look something like this: &lt;code&gt;select a.auditcolumn from auditable a where a.tablename = 'WORKORDERS'&lt;/code&gt;. The list of resulting &lt;code&gt;auditcolumn&lt;/code&gt;s tells us what values from our workorder records we have to add in to the &lt;code&gt;audittrail&lt;/code&gt; table.&lt;/li&gt;&lt;li&gt;For each auditcolumn, get the before value and after value from the inserted or updated record and store them in the &lt;code&gt;audittrail&lt;/code&gt; table.&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;The ugly part is that I have to explicitly call the sproc to do the auditing rather than leverage a trigger to do the work for me. And the &lt;em&gt;really&lt;/em&gt; ugly part is that I need to avoid user the vendor&amp;rsquo;s sprocs and replicate the business logic in C# code in the MOM. There are some historical reasons for this that are not relevant to this discussion, but the point remains: because I have to avoid the vendor sprocs &amp;ldquo;business logic interface&amp;rdquo; and because the auditing is not handled by triggers, I&amp;rsquo;m faced with figuring out the auditing with my tool of choice, NHibernate. The selection of NHibernate was driven primarily by the need for my MOM to have transparent support for both Oracle and SQL Server. SubSonic appears to have some holes related to Oracle that my co-workers have found, and Entity Framework is too new for me to be building a cross platfrom product core on top of. I am concerned that some of the wackier edge cases like auditing and composite keys will trip me up.&lt;/p&gt;&lt;p&gt;In summary, I have a legacy database with a wonky auditing feature, I cannot use the current set of vendor sprocs, and I need to be absolutely sure that when my MOM is creating and updating records that I create the audit trail.&lt;/p&gt;&lt;h4&gt;NHibernate Events and Aspect Oriented Programming&lt;/h4&gt;&lt;p&gt;Of course this sounds like a perfect place to use some &lt;abbr title="aspect oriented programming"&gt;&lt;a href="http://en.wikipedia.org/wiki/Aspect-oriented_programming"&gt;AOP&lt;/a&gt;&lt;/abbr&gt; jujitsu because the auditing function is cross cutting in nature, just like logging or security authorization. In other words, the act of creating a workorder or updating an employee record are tasks that a developer would need to understand and account for. But the auditing itself is orthogonal to the main task at hand and thus should be handled elsewhere in the code. Frameworks like Spring in the Java world and &lt;a href="http://www.postsharp.org/aop-net/overview" title="PostSharp" target="_blank"&gt;PostSharp&lt;/a&gt; for the .NET crowd handle all of the plumbing to enable AOP. But luckily, so does the container that NHibernate uses&amp;mdash;&lt;a href="http://castleproject.org/container/index.html" title="Windsor Container" target="_blank"&gt;the Castle project&amp;rsquo;s Windsor Container&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Here&amp;rsquo;s the basic idea of AOP then. I should be able to create a class or implement and interface or listen for an event in my application code and tell the AOP framework to catch that event and do something with it. One of the canonical examples for AOP is logging; rather than litter my code with &lt;code&gt;Log.Debug("some message")&lt;/code&gt; or &lt;code&gt;Log.Fatal("boom!")&lt;/code&gt; I would rather tell the AOP framework to listen for any method call and write a debug statement, or listen for any unhandled exception and send an email to the system administrator. The Windsor Container (I&amp;rsquo;ll just call it Windsor from here on out) can do exactly that for me, and the NHibernate developers have built extensibility points in to the persistence lifecycle to help me. Enter NHibernate events.&lt;/p&gt;&lt;p&gt;These NH events were added at v2.0 and are a set of interfaces that I can implement to do things like, oh, I don't know...auditing! For example, there is an interface called &lt;code&gt;IPostInsertEventListener&lt;/code&gt; that I can implement. If I then tell NH that I want to use my implementation of &lt;code&gt;IPostInsertEventListener&lt;/code&gt; by adding it during the configuration stage of NH startup, then my code in the &lt;code&gt;OnPostInsert&lt;/code&gt; method will run &lt;em&gt;every single time a record is inserted or updated&lt;/em&gt; in the database. As you might imagine, when I realized the consequences of having this capability at my fingertips, I got a little giddy! After all this turned out to be the magic bullet I was looking for to solve my crazy auditing problem. Seems like I should be able to run through the steps I described above in that &lt;code&gt;OnPostInsert&lt;/code&gt; method and add my audit records using the before and after values. Now, I'm more of a look-at-someone-elses-implementation-and-modify-it kind of guy, so I trolled around on the Internet and found a couple of great resources beyond the standard &lt;a href="http://www.nhforge.net" target="_blank"&gt;NHibernate docs&lt;/a&gt;.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Ayende has a &lt;a href="http://ayende.com/Blog/archive/2009/04/29/nhibernate-ipreupdateeventlistener-amp-ipreinserteventlistener.aspx" target="_blank"&gt;great blog post&lt;/a&gt; describing almost precisely what I need to do. He&amp;rsquo;s one of the committers on NH as well so I felt like his advice was pretty sound.&lt;/li&gt;&lt;li&gt;Rob Reynolds also read Ayende&amp;rsquo;s post and applied it specifically to an auditing event listener so I read &lt;a href="http://ferventcoder.com/archive/2009/11/18/nhibernate-event-listener-registration-with-fluent-nhibernate.aspx" target="_blank"&gt;his approach&lt;/a&gt; with great interest as well.&lt;/li&gt;&lt;/ul&gt;&lt;h4&gt;The pieces are all there. How to actually do it.&lt;/h4&gt;&lt;p&gt;Having done all of the research I was able to whip up my cross-cutting auditing event handler in pretty short order. Here&amp;rsquo;s the complete code, with some of the vendor specific stuff ellided and obfuscated for non-disclosure reasons:&lt;/p&gt;&lt;script src="http://gist.github.com/250479.js?file=EventListener.cs"&gt;&lt;/script&gt;&lt;p&gt;As you can see I capture every single insert or update event in my system and then look for the &lt;code&gt;IAuditable&lt;/code&gt; marker interface that I created for that purpose. If I actually have an &lt;code&gt;IAuditable&lt;/code&gt; class then I proceed to handle the specific cases. Right now I just need to do workorders but expanding this is trivially easy. You can see where I then use some attributes to map between the properties/fields in my class and the column names in the database. I did try to mine the NHibernate metadata to avoid this (you can &lt;a href="http://stackoverflow.com/questions/1800930/getting-class-field-names-and-table-column-names-from-nhibernate-metadata" title="Stack Overflow" target="_blank"&gt;read about my frustrations elsewhere&lt;/a&gt;) but ultimately went with a bit of duplication of metadata to avoid a much bigger headache in the long run. This is, after all, a consulting gig and I can only futz around for so long before I just have to get the darn thing working.&lt;/p&gt;&lt;p&gt;How to configure NHibernate to use this? Well I&amp;rsquo;m using &lt;a href="http://fluentnhibernate.org/" title="Fluent HNibernate" target="_blank"&gt;Fluent NHibernate&lt;/a&gt; for this project and luckily for me &lt;a href="http://ferventcoder.com/archive/2009/11/18/nhibernate-event-listener-registration-with-fluent-nhibernate.aspx" title="Fervent Code" target="_blank"&gt;Rob Reynolds had again beat me to it&lt;/a&gt;. I essentially copied his code and arrived at this to hook it all together. Yep, just one extra line of code in my config setup :-)&lt;/p&gt;&lt;pre&gt;Configuration cfg = GetDbConnectionConfiguration(Resources.CityworksDatasource);&lt;br /&gt;  Fluently.Configure(cfg)&lt;br /&gt;   .ExposeConfiguration(c =&gt;&lt;br /&gt;    c.EventListeners.PostInsertEventListeners = new IPostInsertEventListener[] { new AuditEventListener() })&lt;br /&gt;   .Mappings(m =&gt; m.FluentMappings&lt;br /&gt;    .Add&lt;WorkorderMap&gt;()&lt;br /&gt;    ... // Lots more mappings&lt;br /&gt;    .Add&lt;AuditedItemMap&gt;()&lt;br /&gt;   .BuildConfiguration();&lt;br /&gt;  return cfg;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;So there you have it, a very clean way to leverage the Windsor/NHibernate AOP extensibility point to make a messy auditing story a lot easier to swallow.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3131102996085923653-5921945564339150866?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/5921945564339150866/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/12/nhibernate-events-to-rescue.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/5921945564339150866'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/5921945564339150866'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/12/nhibernate-events-to-rescue.html' title='NHibernate Events to the rescue'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-2240394214430665746</id><published>2009-11-24T09:54:00.000-08:00</published><updated>2009-11-24T09:59:10.575-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><title type='text'>I love unit test results that are green</title><content type='html'>&lt;p&gt;I've been working on a fairly complex legacy database integration using NHibernate. Several "implied" (a.k.a. missing) relationships, composite keys, magic strings where "B" means projected and empty means...not sure actually. So my unit tests are really a life saver. Every time I add a feature I have the benefit of knowing that I'm getting closer without doing things that are going to bite me later. Yes, my tests could be poorly written in some cases, yes I'm hitting the database way more than I should, but I'll take it as the price for my TDD comfort blanket.&lt;/p&gt;&lt;img src="http://2.bp.blogspot.com/_-FppOh0pKM8/SwwepZyC6aI/AAAAAAAAEv8/Ezp74rsIwXo/s800/unit-tests.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5407730949209385378" /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3131102996085923653-2240394214430665746?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/2240394214430665746/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/11/i-love-unit-test-results-that-are-green.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/2240394214430665746'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/2240394214430665746'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/11/i-love-unit-test-results-that-are-green.html' title='I love unit test results that are green'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_-FppOh0pKM8/SwwepZyC6aI/AAAAAAAAEv8/Ezp74rsIwXo/s72-c/unit-tests.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-672451149268065250</id><published>2009-11-20T14:42:00.000-08:00</published><updated>2009-11-20T14:48:51.505-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='general'/><title type='text'>Bad Explanation</title><content type='html'>&lt;p&gt;I have officially discovered the worst slide describing REST. Not because the explanation itself is particularly poor. But the visual noise is just too much to bear. I actually stopped watching &lt;a href="http://mediacast.sun.com/users/caroljmcdonald/media/restproject.swf"&gt;the presentation&lt;/a&gt; immediately. Here's the offending slide at 0:21&lt;/p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_-FppOh0pKM8/SwcciD7pUfI/AAAAAAAAEvQ/VVQCycKKJ7w/s1600/rest.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://3.bp.blogspot.com/_-FppOh0pKM8/SwcciD7pUfI/AAAAAAAAEvQ/VVQCycKKJ7w/s400/rest.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5406321249178178034" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3131102996085923653-672451149268065250?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/672451149268065250/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/11/bad-explanation.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/672451149268065250'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/672451149268065250'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/11/bad-explanation.html' title='Bad Explanation'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_-FppOh0pKM8/SwcciD7pUfI/AAAAAAAAEvQ/VVQCycKKJ7w/s72-c/rest.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-5791484410623874943</id><published>2009-11-16T16:07:00.000-08:00</published><updated>2009-11-22T11:43:36.903-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='offtopic'/><title type='text'>Visual Studio theme - Ruby Blue knockoff</title><content type='html'>&lt;p&gt;In the &amp;ldquo;can&amp;rsquo;t possible face another line of code&amp;rdquo; category for today I spent a few minutes changing colors in Visual Studio. It's not exactly rocket science but sometimes you just need to do something different to refresh the brain cells. I kind of like this darker-but-not-black look to reduce eye strain. It's a total knockoff of John Long's &lt;a href="http://wiseheartdesign.com/articles/2006/03/11/ruby-blue-textmate-theme/"&gt;TextMate theme&lt;/a&gt;. &lt;a href="http://gist.github.com/236449" title="Visual Studio theme"&gt;Download the theme&lt;/a&gt; from GitHub and using your &lt;code&gt;Import/Export Settings&lt;/code&gt; option to pull them in. I just exported the colors and fonts so you should not see any other settings change.&lt;/p&gt;&lt;img src="http://2.bp.blogspot.com/_-FppOh0pKM8/SwHqU9lP_jI/AAAAAAAAEvI/mgZkl2c7MQ8/s800/ruby-blue.png" alt="screenshot"/&gt;&lt;p&gt;UPDATE: And you can probably tell that I like the &lt;a href="http://www.webdevkungfu.com/textmate-envy-aka-monaco-font-for-windows/"&gt;Monaco&lt;/a&gt; font for my fixed-width viewing pleasure.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3131102996085923653-5791484410623874943?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/5791484410623874943/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/11/visual-studio-theme-ruby-blue-knockoff.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/5791484410623874943'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/5791484410623874943'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/11/visual-studio-theme-ruby-blue-knockoff.html' title='Visual Studio theme - Ruby Blue knockoff'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_-FppOh0pKM8/SwHqU9lP_jI/AAAAAAAAEvI/mgZkl2c7MQ8/s72-c/ruby-blue.png' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-6349496796988322903</id><published>2009-11-13T19:19:00.000-08:00</published><updated>2009-11-13T19:54:57.892-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='patterns'/><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><title type='text'>Circuit Breaker of the non-electrical variety</title><content type='html'>&lt;p&gt;You all know about circuit breakers. They protect electrical networks and devices from surges by opening up when the bad stuff happens. Basically they are a binary toggle: a circuit breaker that is closed ensures that electricity can flow unimpeded through a medium like good old copper wires. A circuit breaker that is open...well...doesn't. It protects our expensive gadgets like computers and toasters from spikes in the supply. I may work for an engineering company, but that just exhausted my knowledge of what an actual, physical circuit breaker does.&lt;/p&gt;&lt;p&gt;But what about protecting software from volatile resources in their own systems? I can't remember how many times I've assumed that a website was running when attempting to call it, or how many #*(#%$#@! &lt;abbr title="Windows Communication Foundation"&gt;WCF&lt;/abbr&gt; services I've depended on in a "loosely coupled" system for critical things like, oh I don't know...security! I guess my loosely coupled systems are still prone to massive failures when some innocuous part decides to puke. I'm sure you've had this happen before: a database that didn't work, an file transfer that was just too slow. Enter the Circuit Breaker.&lt;/p&gt;&lt;h4&gt;Release It!&lt;/h4&gt;&lt;p&gt;In most excellent book &lt;a href="http://www.pragprog.com/titles/mnee/release-it"&gt;Release It!&lt;/a&gt; Michael T. Nygard presents many approaches to deploy fault tolerant software into the wild. We all know how easy it is to build software. We all know that it can bring a business to it's knees when said software doesn't work right. Personally I'm thinking about an embarrassing tool I wrote that crashed and burned when access to an FTP site wasn't there. Totally missed it during coding, got bit in the ass when a deployed system failed spectacularly. No details necessary. Suffice it say that shame caused me to seek out ways to make my deliverable more tolerant of the daily hiccups we all identify with. But Nygard's book is a real revelation me and many others in the pragmatic advice he gives to protect systems against just such failures. And of course, one "pattern" he advocates is the use of Circuit Breakers (big C and B).&lt;/p&gt;&lt;p&gt;It goes something like this:&lt;ol&gt;&lt;li&gt;Software calls an unreliable service like "Bob's automated electronic knife sharpening service". For some unfathomable reason this works the first time around. All good.&lt;/li&gt;&lt;li&gt;The next time we call the service it times out. Oh no! Disaster! Except we handle the error nicely &lt;em&gt;and increment our "screw up" counter by one&lt;/em&gt;.&lt;/li&gt;&lt;li&gt;We try again (darn user just keeps clicking the "sharpen my knife on the internet button") and the thing fails again. No problem - we again catch the error and tell the use "Whoops!" and &lt;em&gt;increment the "screw up" counter again&lt;/em&gt;. We now have two service failures. We have also configured our system to stop the madness if a service fails three times in a row.&lt;/li&gt;&lt;li&gt;Of course, the user clicks the button again immediately, thus ignoring all of our strongly worded advice that "it ain't going to work". Our "screw up" counter hits three and guess what? The circuit trips. Somewhere in our calling code we decide that enough is enough and we should just open the circuit and stop these requests to the unreliable service for a while. We hope beyond hope that just waiting a while, like maybe 30 seconds in a web application, will give Bob's Knife Sharpening Service time to recover.&lt;/li&gt;&lt;li&gt;Wouldn't you know it...the user &lt;em&gt;still&lt;/em&gt; presses the darn button. But this time we stop the madness and immediately and instantly report back that the circuit is open and request cannot go through. Or a popup saying "Knife sharpening is busy...try again in a minute or two". Or we disable the offending button. Whatever we present to the user, the important part is that a timer is fired up when the circuit trips open and no amount of button clicking will induce our cleverly protected system to call the unstable service until the timeout period has expired.&lt;/li&gt;&lt;/ol&gt;&lt;/p&gt;&lt;p&gt;Do you get the idea? We are essentially trying to stop a bad situation from getting worse. We all know that when a remote service is down, the last thing we should do is to just keep right on calling it. We should give it a chance to catch it's breath. That's what the Circuit Breaker gives us.&lt;/p&gt;&lt;h4&gt;C# Circuit Breaker, Anyone?&lt;/h4&gt;&lt;p&gt;I've been burned enough time that I wanted to implement CB on my current project. Hey, who am I to ignore 100 years of sound electrical advice, let alone 5 year old software engineering wisdom? I found some really excellent implementations that all approach the problem from slight different angles. In particular the canonical (or first, at least) version came from &lt;a href="http://timross.wordpress.com/2008/02/10/implementing-the-circuit-breaker-pattern-in-c/"&gt;Tim Ross&lt;/a&gt;. This was followed up earlier in 2009 by the prolific &lt;a href="http://davybrion.com/blog/"&gt;Davy Brion&lt;/a&gt; in a great &lt;a href="http://davybrion.com/blog/2009/07/protecting-your-application-from-remote-problems/"&gt;blog post&lt;/a&gt; that laid it all out there. Davy uses the Castle Windsor inversion of control container to do some fancy aspect oriented stuff using interceptors (and if you understand that sentence they I think we would enjoy drinking a beer together). For my current project that is all a bit too much, plus I'm using &lt;a href="http://structuremap.sourceforge.net/"&gt;StructureMap&lt;/a&gt;, so I made a couple of &lt;i&gt;very&lt;/i&gt; minor tweaks to his code to get up and running. Here's the implementation. Notice how the CB used a state pattern and failure counter but is really all about invoking an &lt;code&gt;Action&lt;/code&gt;.&lt;/p&gt;&lt;script src="http://gist.github.com/234358.js"&gt;&lt;/script&gt;&lt;p&gt;In my heartbeat service (health monitor for a web site) I do something very, very simple and test resources. The crux of the whole thing is to wrap that call to the potentially unreliable remote resource inside the circuit breaker:&lt;/p&gt;&lt;script src="http://gist.github.com/234356.js"&gt;&lt;/script&gt;&lt;p&gt;I've included a couple of unit tests so that you can see how it all ties together&lt;/p&gt;&lt;h4&gt;Summary&lt;/h4&gt;&lt;p&gt;The circuit breaker protects a system from potentially unreliable dependencies. It does &lt;em&gt;not&lt;/em&gt; bury the errors but actually let's the calling application still be fully aware of the exceptions. But it &lt;em&gt;does&lt;/em&gt; draw a line in the sand by way of a failure threshold and stops an excessive number of calls to the bad resource. That is the essence of controlled failure. Let the thing break, but don't let the break cause a cascading meltdown to your carefully crafted calling system. Handle the unpredictability by opening the circuit.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3131102996085923653-6349496796988322903?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/6349496796988322903/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/11/circuit-breaker-of-non-electrical.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/6349496796988322903'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/6349496796988322903'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/11/circuit-breaker-of-non-electrical.html' title='Circuit Breaker of the non-electrical variety'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-4962260126828706500</id><published>2009-11-12T20:09:00.001-08:00</published><updated>2009-11-13T10:48:50.995-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='general'/><title type='text'>Programming Opinions</title><content type='html'>&lt;p&gt;Few things start flame wars faster than an open ended question addressed to a bunch of programmers. There's a really &lt;a href="http://stackoverflow.com/questions/406760/whats-your-most-controversial-programming-opinion/406848"&gt;great question&lt;/a&gt; on &lt;a href="http://www.stackoverflow.com"&gt;Stack Overflow&lt;/a&gt; that appears to be breaking the mold on that front. The contention is that most developers will have a controversial opinion or two up their sleeve. As it happens, many of  the "controversial" opinions so far seem to be quite sensible. A couple of my favorites:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;strong&gt;If you only know one language, no matter how well you know it, you're not a great programmer.&lt;/strong&gt;&lt;br/&gt;There seems to be an attitude that says once you're really good at C# or Java or whatever other language you started out learning then that's all you need. I don't believe it- every language I have ever learned has taught me something new about programming that I have been able to bring back into my work with all the others. I think that anyone who restricts themselves to one language will never be as good as they could be.&lt;br/&gt;It also indicates to me a certain lack of inquisitiveness and willingness to experiment that doesn't necessarily tally with the qualities I would expect to find in a really good programmer.&lt;p&gt;&lt;h4&gt;My Take&lt;/h4&gt;Amen! I was just telling Kirk that the only reason my C# is doing as well as it is (I'm modest too) is that I read a lot of Ruby and Python recently. Lambdas and other functional bits like list comprehensions and map/reduce have deepened my understanding of LINQ and the whole Func/Action thing. "I'm a .NET Developer" to me sounds a bit silly. How about "I've done a lot of .NET work but give me a web connection and some good source code to look at and I could do the project in [INSERT LANGUAGE HERE]."&lt;br/&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;If you're a developer, you should be able to write code&lt;/strong&gt;&lt;br/&gt;I did quite a bit of interviewing last year, and for my part of the interview I was supposed to test the way people thought, and how they implemented simple-to-moderate algorithms on a white board. I'd initially started out with questions like:&lt;br/&gt;Given that Pi can be estimated using the function 4 * (1 - 1/3 + 1/5 - 1/7 + ...) with more terms giving greater accuracy, write a function that calculates Pi to an accuracy of 5 decimal places.&lt;br/&gt;It's a problem that should make you think, but shouldn't be out of reach to a seasoned developer (it can be answered in about 10 lines of C#). However, many of our (supposedly pre-screened by the agency) candidates couldn't even begin to answer it, or even explain how they might go about answering it. So after a while I started asking simpler questions like:&lt;br/&gt;Given the area of a circle is given by Pi times the radius squared, write a function to calculate the area of a circle.&lt;br/&gt;Amazingly, more than half the candidates couldn't write this function in any language (I can read most popular languages so I let them use any language of their choice, including pseudo-code). We had "C# developers" who could not write this function in C#.&lt;br/&gt;I was surprised by this. I had always thought that developers should be able to write code. It seems that, nowadays, this is a controversial opinion. Certainly it is amongst interview candidates!&lt;p&gt;&lt;h4&gt;My Take&lt;/h4&gt;Jesus!!! I would have crashed and burned on that one. My math is rudimentary and based upon Google searches. I even bought a beginners guide to pre-calculus recently. Yes, we need to be able to write code, but lets stick to realistic problems. I'm much more likely to ask a question like the FizzBuzz one, or ask a candidate to walk me through pseudo code for an elevator control system. If they can actually THINK through that design exercise then I can teach them how to code it.&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;So yeah, that's a really thought provoking question that has spawing lots of interesting discussion. Have a troll through the responses and let me know what you think is "controversial" and what is just common sense.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3131102996085923653-4962260126828706500?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/4962260126828706500/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/11/programming-opinions.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/4962260126828706500'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/4962260126828706500'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/11/programming-opinions.html' title='Programming Opinions'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-3000242185364996393</id><published>2009-11-04T21:22:00.001-08:00</published><updated>2009-11-22T11:48:20.546-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>Rake for .NET Projects</title><content type='html'>&lt;p&gt;I'm working on a .NET project right now that involves 3 (or is it 4?) developers on two different teams in 3 different locations. The usual dance is being played with different dev settings for each person, like "use this GIS server for these layers" and "use this Oracle TNS for that database, but SQL Server for the other one". Not to mention the need to update a bunch of JSON configuration files depending on who is building the project. So I thought I'd take a look at the Rake build system that is written in Ruby. Actually, because I know there would be a revolution if the developers had to install Ruby just to update some files, I went with IronRuby instead. This is the version of Ruby that is being built to run on the .NET Framework. The beauty of it (apart from a slow startup time) is the speed of execution, and an xcopy deployment for any machine that already has .NET installed. Which is every Windows PC out there.&lt;p&gt;&lt;p&gt;So how does this work? Well, I first &lt;a href="http://www.ironruby.net/Download"&gt;downloaded IronRuby&lt;/a&gt; (get the ZIP file not the MSI installer) and unzipped it into the &lt;code&gt;trunk\tools&lt;/code&gt; directory of my project. I followed the excellent advice of &lt;a href="http://www.evanclosson.com/devlog/ironrakeironrubyakagoodbyenant"&gt;Evan Closson&lt;/a&gt; and created a little batch file that sets up my Ruby environment such that commands like &lt;code&gt;iirb&lt;/code&gt; and &lt;code&gt;irake&lt;/code&gt; actually cause the expected thing to happen. Ignore the stuff about 7-zip for now. I added that later and will explain.&lt;/p&gt;&lt;script src="http://gist.github.com/226796.js"&gt;&lt;/script&gt;&lt;p&gt;After getting what amounts to a zero-installer, xcopy deployment of the entire Ruby language running in 3 minutes, we then need to get Rake. Ruby has a wonderful package management system called Gems. By typing &lt;code&gt;igem install rake&lt;/code&gt; (don't miss the "i" there...that's IronRuby you're running!), Rake is downloaded and installed in to my &lt;code&gt;trunk\tools\ironruby\lib\ruby\gems\1.8\gems\rake-0.8.7&lt;/code&gt; directory. I had unzipped my IronRuby download in to the ironruby directory, and the rest was done for me. Test thinks out by typing &lt;code&gt;irake&lt;/code&gt;. It'll barf at you because it's got nothing to do, but at least you now have the environment all squared away.&lt;/p&gt;&lt;p&gt;Next I compressed my IronRuby directory, complete with Rake, into a &lt;a href="http://7-zip.org/"&gt;7-zip&lt;/a&gt; file called &lt;code&gt;ironruby.7z&lt;/code&gt; and then deleted my ironruby directory. The resulting file is about 2MB is size and suitable to put in subversion. Large files need not apply! I also have the 7-zip executable in my &lt;code&gt;trunk\tools&lt;/code&gt; directory so that my init.bat file can uncompress it on demand when a new developer downloads the code for the first time. (note: if you're not using 7-zip yet then drop everything, go and install it, then carry on reading).&lt;/p&gt;&lt;p&gt;That leaves us with this directory structure (omitted the irrelevant parts). You can see how the JSON resources that I want to update per user are in the resource directory of my websites, and that the ConnectionStrings.config.template is at the top of the source directory. I link to this file from every project in the solution that needs access to databases so that the Web.config or App.config simply has &lt;connectionStrings configSource="bin\ConnectionStrings.config" /&gt; in it and updating the one file automatically squares away any other application.&lt;/p&gt;&lt;img src="http://2.bp.blogspot.com/_-FppOh0pKM8/SvMCgHJIcJI/AAAAAAAAEvA/tQ0Iw1VTyS8/s1600/mockup_2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5400663128843776146" /&gt;&lt;h3&gt;Rake&lt;/h3&gt;&lt;p&gt;Big deal. I have Ruby and rake. So what? Again following Evan's advice I created a few files. Rake expects a file called &lt;code&gt;rakefile.rb&lt;/code&gt; or just plain &lt;code&gt;rakefile&lt;/code&gt; to live in the directory from which it is executed. In my case this means in my trunk directory. But I don't want to clutter things up so I also created a &lt;code&gt;trunk\source\tasks&lt;/code&gt; directory to hold the two build scripts that really do the work: &lt;code&gt;build.rb&lt;/code&gt; and &lt;code&gt;rakefile.rb&lt;/code&gt;. First comes the rakefile:&lt;/p&gt;&lt;script src="http://gist.github.com/226800.js"&gt;&lt;/script&gt;&lt;p&gt;As you might be able to tell, this is reading in some settings in the YAML (YAML ain't another markup language, I think) format. The yaml format is essentially the de facto Ruby serialization format, so by using yaml I get free conversion from a text file to a ruby object simply by calling YAML.load_file. Exactly the same as if I were to read a JSON file in to JavaScript - implicit understanding of the content. Here's a yaml file:&lt;/p&gt;&lt;script src="http://gist.github.com/226804.js"&gt;&lt;/script&gt;&lt;p&gt;The structure is very simple and can be created in a text editor. Assuming the user starts the build process with &lt;code&gt;irake DEPLOY=production&lt;/code&gt; then the production values are used. If they enter &lt;code&gt;irake DEPLOY=development&lt;/code&gt; or just &lt;code&gt;irake&lt;/code&gt; without a parameter then the dev settings are used. Amazing! Astounding! Just so much better than msbuild that I've struggled with.&lt;/p&gt;&lt;blockquote&gt;Full disclosure: I'm not just spouting off here. I've written a few fairly ambitious and complex build scripts using msbuild. It works, it's powerful, and it's a bugger to use and learn. This rake business, on the other hand, is the first time I've ever touched Ruby and I'm not looking back. So there.&lt;/blockquote&gt;&lt;br /&gt;&lt;p&gt;OK, we've got our configs. Now what do we do with them? My use case is simple: I need to update a boat load of JSON files and a single web.config file with some fresh server names, connection strings, and the like. Here's what &lt;code&gt;build.rb&lt;/code&gt; looks like:&lt;/p&gt;&lt;script src="http://gist.github.com/226805.js"&gt;&lt;/script&gt;&lt;p&gt;Rake is geared towards completing tasks. It is a build system, after all. First thing to notice is the default task. Just like every other system out there like make, ant, nant, msbuild, bake, psake, etc., it can have dependencies. So when I run &lt;code&gt;irake&lt;/code&gt; it looks for a rakefile, then looks for a task called default. Finding that it then runs &lt;code&gt;update_user_configs&lt;/code&gt; which in turn runs &lt;code&gt;create_user_files&lt;/code&gt; which... It's obviously turtles all the way down from there - just keep following the dependency trail.&lt;/p&gt;&lt;p&gt;You can, dear programmer, probably figure out the rest of what is happening because Ruby is pretty expressive and clear (mostly!). For example, notice the &lt;code&gt;'require rexml/document'&lt;/code&gt;. REXML is the core Ruby XML processing library and I use that in the &lt;code&gt;update_connection_strings&lt;/code&gt; task on line 84. If you've written any .NET applications you can tell that I'm opening up app.config or web.config files in the solution and doing a search and replace for a series of database connection strings. Look back at the YAML to refresh your memory. It's simple and I can literally cut'n'paste this task in to any one of my other .NET projects that need to have developer-specific connection strings in them.&lt;/p&gt;&lt;h3&gt;Summary&lt;/h3&gt;&lt;p&gt;I'm getting tired of typing here so I'll summarize briefly. IronRuby is a version of Ruby that is written in C# and runs on the CLR. It can use standard Ruby plugins or Gems such as Rake. Rake is a build system that uses regular Ruby code and files instead of XML to make writing build scripts less painful. I'm sure I've missed some key details in describing my setup. Let me know if you're confused by any steps and I'll do my best to update this post.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3131102996085923653-3000242185364996393?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/3000242185364996393/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/11/rake-for-net-projects.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/3000242185364996393'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/3000242185364996393'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/11/rake-for-net-projects.html' title='Rake for .NET Projects'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_-FppOh0pKM8/SvMCgHJIcJI/AAAAAAAAEvA/tQ0Iw1VTyS8/s72-c/mockup_2.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-6256934382953500119</id><published>2009-10-16T09:48:00.000-07:00</published><updated>2009-12-11T11:30:41.908-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='utility'/><category scheme='http://www.blogger.com/atom/ns#' term='structuremap'/><title type='text'>StructureMap Registry</title><content type='html'>&lt;p&gt;This is more for my information but feel free to look. I have centralized all object dependencies in my current project and have settled on the &lt;a href="http://structuremap.sourceforge.net/Default.htm"&gt;StructureMap&lt;/a&gt; IoC container as the coordinator. It took me a while to figure this out because I have two databases configured with NHibernate and depending on which repository I'm using I need to point to different NHibernate ISessionFactory instances. This was getting complicated so I created a simple unit of work class to manage the details, and was left with a much cleaner config. Admittedly this may look complicated to the uninitiated, but it's a lot easier that spreading all this stuff throughout my entire code base.&lt;/p&gt;&lt;p&gt;As usual, if you can't see the code it's because I'm lazy and I'm using &lt;a href="https://github.com/"&gt;github&lt;/a&gt;. You have to open the actual blog page for the good stuff :-)&lt;/p&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/211889.js"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3131102996085923653-6256934382953500119?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/6256934382953500119/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/10/structuremap-registry.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/6256934382953500119'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/6256934382953500119'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/10/structuremap-registry.html' title='StructureMap Registry'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-65128305625099969</id><published>2009-10-15T20:18:00.000-07:00</published><updated>2009-10-15T20:21:01.858-07:00</updated><title type='text'>SQL Server and firewalls</title><content type='html'>I keep forgetting to open up port 1433 to access SQL Server 2008 on the network. Did a little searching and found &lt;a href="http://www.robkerr.com/post/2008/07/Windows-Firewall-and-SQL-Server-2008.aspx"&gt;this post&lt;/a&gt; that shows how to use the &lt;term&gt;netsh&lt;/term&gt; command to do it all in a script. For example:&lt;br /&gt;&lt;pre&gt;netsh firewall set portopening TCP 1433 "SQLServer"&lt;/pre&gt;&lt;br /&gt;Much better than going through the Windows Firewall user interface because you can set a bunch of exceptions in one script.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3131102996085923653-65128305625099969?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/65128305625099969/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/10/sql-server-and-firewalls.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/65128305625099969'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/65128305625099969'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/10/sql-server-and-firewalls.html' title='SQL Server and firewalls'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-4345407738871814457</id><published>2009-10-14T12:45:00.001-07:00</published><updated>2009-10-14T12:45:37.081-07:00</updated><title type='text'>RegEx to the rescue: finding “between” matches</title><content type='html'>&lt;p&gt;I grabbed the source code of a web page to extract a bunch of train station locations in Chicago. After a little bit of vim’ing I had cleaned up the majority of the guff that I didn’t need. But I had hundreds of lines of Google Maps JavaScript to parse out so that I could get a CSV file to map my station locations. The problem was some goofy HTML mixed in with the JavaScript. I needed everything except the text between the colon after the station name and the two or three character station identifier.&lt;/p&gt;  &lt;pre&gt;&lt;p&gt;41.7266667, -87.5477778, 93rd St. (South Chicago) Station:&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;93rd St. near Baltimore St.&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;Chicago,IL&amp;lt;/dd&amp;gt;&amp;lt;ul&amp;gt;&amp;lt;li class=\&amp;quot;line me&lt;br /&gt;41.7055556, -87.6558333,103rd St. - Washington Hts.&amp;#160; Station:&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;10335 S. Vincennes Ave.&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;Chicago,IL&amp;lt;/dd&amp;gt;&amp;lt;ul&amp;gt;&amp;lt;li class=\&amp;quot;line ri&lt;br /&gt;41.7069444, -87.6072222,103rd Street (Rosemoor) Station:&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;103th St. &amp;amp; Cottage Grove Ave.&amp;lt;/dd&amp;gt;&amp;lt;dd&amp;gt;Chicago,IL&amp;lt;/dd&amp;gt;&amp;lt;ul&amp;gt;&amp;lt;li class=\&amp;quot;line me&lt;/p&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;So, I cracked open &lt;a href="http://www.regexbuddy.com/"&gt;RegexBuddy&lt;/a&gt; and started to work. I really don’t get regex at all in spite of many false starts, but RegexBuddy makes life a little easier. After looking at &lt;a href="http://stackoverflow.com/questions/608319/regex-replace-but-only-between-two-patterns"&gt;this great answer&lt;/a&gt; on StackOverflow and working in RegexBuddy I was able to quite easily figure out the solution:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_-FppOh0pKM8/StYqWGMo-4I/AAAAAAAAEtc/Wqb032DPY2g/s1600-h/10-14-2009%2012-42-21%20PM%5B3%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="10-14-2009 12-42-21 PM" border="0" alt="10-14-2009 12-42-21 PM" src="http://lh3.ggpht.com/_-FppOh0pKM8/StYqX5sFpGI/AAAAAAAAEtg/V-jXvkS85zU/10-14-2009%2012-42-21%20PM_thumb%5B1%5D.png?imgmax=800" width="1195" height="649" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;I love that product!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3131102996085923653-4345407738871814457?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/4345407738871814457/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/10/regex-to-rescue-finding-between-matches.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/4345407738871814457'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/4345407738871814457'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/10/regex-to-rescue-finding-between-matches.html' title='RegEx to the rescue: finding “between” matches'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_-FppOh0pKM8/StYqX5sFpGI/AAAAAAAAEtg/V-jXvkS85zU/s72-c/10-14-2009%2012-42-21%20PM_thumb%5B1%5D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-965945591650353785</id><published>2009-10-12T16:24:00.001-07:00</published><updated>2009-10-12T16:26:49.933-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='nhibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><title type='text'>NHibernate HQL Queries I always forget</title><content type='html'>&lt;p&gt;The easy one is the first one - counting rows in a table. Stupid simple but I always forget the UniqueResult bit:&lt;/p&gt;&lt;script src="http://gist.github.com/208835.js"&gt;&lt;/script&gt;&lt;p&gt;And the not-so-obvious but equally useful way to query an object with a composite primary key. You just pass an anonymous instance of the class with the primary key fields set:&lt;/p&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/208839.js"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3131102996085923653-965945591650353785?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/965945591650353785/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/10/nhibernate-hql-queries-i-always-forget.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/965945591650353785'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/965945591650353785'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/10/nhibernate-hql-queries-i-always-forget.html' title='NHibernate HQL Queries I always forget'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-7580938212581373341</id><published>2009-10-04T18:40:00.001-07:00</published><updated>2009-10-04T19:16:38.657-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><category scheme='http://www.blogger.com/atom/ns#' term='topshelf'/><title type='text'>Windows Services the Easy Way</title><content type='html'>&lt;p&gt;For a long time now I’ve been a big fan of creating Windows service projects in .NET using console applications rather than the canned Visual Studio Service Project template. My primary reason initially was to make sure I could debug the service application easily by setting a command line switch rather than monkeying around with attempting to debug a live Windows service. So my typical code would look something like this:&lt;/p&gt; &lt;script src="http://gist.github.com/201658.js"&gt;&lt;/script&gt;  &lt;p&gt;Notice how the first check is to see whether the command line contains a switch called –console? That is something I set up in the DEBUG properties of the Visual Studio project. So whenever I launch the executable during development it acts just like a console app, and I can in fact use that in production as well for testing purposes (-CONSOLE spits out a lot more logging information). If the –console switch isn’t present then the service class—GeneratorHost in this case—starts as a service as usual.&lt;/p&gt;  &lt;h4&gt;TopShelf&lt;/h4&gt;  &lt;p&gt;But I’ve been looking at &lt;a href="http://code.google.com/p/topshelf/"&gt;TopShelf&lt;/a&gt; recently and prefer what I see here as a cleaner approach for testable code. It came from the &lt;a href="http://masstransit.pbworks.com/"&gt;MassTransit&lt;/a&gt; open source .NET service bus project as a way to quickly create service hosts for the large number publishers and subscribers involved in a typical MassTransit implementation, and was then refactored out in to its own project that has, interestingly enough, been coopted by &lt;a href="http://www.udidahan.com/"&gt;Udi Dahan&lt;/a&gt; in his own &lt;a href="http://www.nservicebus.com/"&gt;nServiceBus&lt;/a&gt; project.&lt;/p&gt;  &lt;p&gt;I came across TopShelf mostly because I’ve been pleased with how the MassTransit and nServiceBus approach to distributed systems is shaping up on my current project. I’m using a hand-rolled message queue with a database backend (NHibernate for Oracle, SQL Server, and SQLite support) and making all of my information exchanges be self contained messages that are simply added to the message queue for further processing. The WCF services for web service endpoints and other backend processing code are all hosted as Windows services for ease of deployment and configuration (app.config rather than messing with IIS 6.0). And the nice thing about TopShelf is that it support the IoC container that I’m using these days—&lt;a href="http://structuremap.sourceforge.net/Default.htm"&gt;StructureMap&lt;/a&gt;—and makes debugging &lt;em&gt;and installation/deinstallation &lt;/em&gt;a piece of cake. Not to mention XML config of the user account for the service to run under which is a bonus when dealing with &lt;a href="http://resources.esri.com/help/9.3/arcgisserver/adf/dotnet/api_start.htm"&gt;ArcGIS Server&lt;/a&gt; direct connections.&lt;/p&gt;  &lt;p&gt;So what does it look like? Simply put, there is a fluent configuration API that talks to StructureMap and dynamically builds a Windows service for you without tinkering with ServiceInstaller classes and the like. Here’s an example from my current project where the main purpose of the Windows service is simply to serve as a host to a WCF HTTP service that in turn runs some ArcObjects bits:&lt;/p&gt; &lt;script src="http://gist.github.com/201740.js"&gt;&lt;/script&gt;  &lt;p&gt;I got a bit turned around with the StructureMap / Microsoft.Practices.ServiceLocation facade but the TopShelf source code has a good example of how to implement this. In fact, it was a cut’n’paste job:&lt;/p&gt; &lt;script src="http://gist.github.com/201741.js"&gt;&lt;/script&gt;&lt;h4&gt;Debug, Install, Uninstall&lt;/h4&gt;  &lt;p&gt;The truly great thing about TopShelf, though, is using it in production. Putting the configuration in a console application means that by default running the EXE such as &lt;code&gt;GisDirectQueryHost.exe&lt;/code&gt; runs the “service” without having a Windows service. Running &lt;code&gt;GisDirectQueryHost.exe /install&lt;/code&gt; installs the service and (you saw this one coming) &lt;code&gt;/uninstall&lt;/code&gt; removes it. But in a real hat-tip to flexibility you can install multiple separate instances of the service by adding &lt;code&gt;/install – instance InstanceName&lt;/code&gt;. Now that’s just plain cool. Thank you Kevin Miller for &lt;a href="http://blogs.dovetailsoftware.com/blogs/kmiller/archive/2009/09/24/running-multiple-instances-of-a-windows-service-using-topshelf.aspx"&gt;pointing this out&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/3131102996085923653-7580938212581373341?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/7580938212581373341/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/10/windows-services-easy-way.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/7580938212581373341'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/7580938212581373341'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/10/windows-services-easy-way.html' title='Windows Services the Easy Way'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-1330911723399916191</id><published>2009-10-03T17:17:00.001-07:00</published><updated>2009-10-03T22:45:13.498-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><category scheme='http://www.blogger.com/atom/ns#' term='nettopologysuite'/><category scheme='http://www.blogger.com/atom/ns#' term='utility'/><title type='text'>Transforming ArcGIS Server REST JSON to NetTopologySuite</title><content type='html'>&lt;p&gt;Another quickie: I just wrote some code to get results from a Query against an ArcGIS Server REST server. I put a few classes together than represent fields, layers, and maps. Here the json output from a query (&lt;a href="http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Portland/Portland_ESRI_Neighborhoods_AGO/MapServer/0/query?text=&amp;amp;geometry=&amp;amp;geometryType=esriGeometryEnvelope&amp;amp;inSR=&amp;amp;spatialRel=esriSpatialRelIntersects&amp;amp;where=objectid_1+&amp;lt;+5&amp;amp;returnGeometry=true&amp;amp;outSR=&amp;amp;outFields=*&amp;amp;f=pjson"&gt;like this&lt;/a&gt;) is being passed to my helper function along with a list of fields that I’m interested in keeping, plus the geometry type (like esriPolygon). The wonderful part about this code is the way that &lt;a href="http://james.newtonking.com/pages/json-net.aspx"&gt;Json.NET&lt;/a&gt; assist me with it’s great LINQ implementation and fast forward-only JsonTextReader. In the method below I’m using the JsonTextReader.&lt;/p&gt; &lt;script src="http://gist.github.com/201175.js"&gt;&lt;/script&gt; &lt;p&gt;In the next example I’m ripping through the JSON result with a few lines of LINQ and getting fully built NetTopologySuite geometries that I can convert to GML, WKT, or another useful format. Or simply keep them as-is for analysis purposes.&lt;/p&gt; &lt;script src="http://gist.github.com/201174.js"&gt;&lt;/script&gt; Well, I haven't the polygon stuff yet (blush!) but you get the picture. Getting usable polylines from the JSON is literally two LINQ queries and one &lt;code&gt;foreach&lt;/code&gt; . The simplicity is just a thing of beauty. Oh, and props to &lt;a href="http://stackoverflow.com/questions/1423523/json-net-and-arrays-using-linq"&gt;this guy&lt;/a&gt; for helping past a hurdle.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3131102996085923653-1330911723399916191?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/1330911723399916191/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/10/transforming-arcgis-server-rest-json-to.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/1330911723399916191'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/1330911723399916191'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/10/transforming-arcgis-server-rest-json-to.html' title='Transforming ArcGIS Server REST JSON to NetTopologySuite'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-4035149813900697442</id><published>2009-10-03T17:02:00.001-07:00</published><updated>2009-10-05T08:45:44.791-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='arcobjects'/><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><category scheme='http://www.blogger.com/atom/ns#' term='nettopologysuite'/><category scheme='http://www.blogger.com/atom/ns#' term='utility'/><title type='text'>Converting ESRI geometries to GeoAPI geometries</title><content type='html'>&lt;p&gt;a.k.a. making ESRI data useful.&lt;/p&gt;  &lt;p&gt;I need to do a little lightweight processing on some spatial data. The data is coming from an ESRI geodatabase in the form a IGeometry objects. One of the things I need to do is figure out the “middle” of points, lines, and polygons. Points and polygons are easy: the centroid. Lines are a little more problematic because what I want the “middle” point of a line to be is 50% the way along the length of the line. This is a pain using ArcObjects (ok, not impossible but still annoyingly opaque to my lame ArcObjects skills) and I know how to do it using NetTopologySuite. So I found a nice little utility in an ESRI forums post (that I can no longer find) that shows how to convert ESRI IGeometries to GeoAPI geometries. GeoAPI, as you may know, is the format that NTS uses.&lt;/p&gt;&lt;script src="http://gist.github.com/201187.js"&gt;&lt;/script&gt;  &lt;p&gt;I’ve posted &lt;a href="http://code.google.com/p/dylansknowledgebase/source/browse/trunk/spatial/Spatial.Formats/Spatial.Formats/Converters.cs"&gt;my slightly modified version&lt;/a&gt; of the Converter I found on Google Code, and here is how I’m using the class in a simple ArcGIS Server web service:&lt;/p&gt; &lt;script src="http://gist.github.com/202198.js"&gt;&lt;/script&gt;&lt;p&gt;You can see the usage of NetTopologySuite’s LengthIndexedLine to do a simple bit of linear referencing based upon distance. Simple yes, effective, yes.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3131102996085923653-4035149813900697442?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/4035149813900697442/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/10/converting-esri-geometries-to-geoapi.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/4035149813900697442'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/4035149813900697442'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/10/converting-esri-geometries-to-geoapi.html' title='Converting ESRI geometries to GeoAPI geometries'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-3985762318323451088</id><published>2009-08-31T22:44:00.000-07:00</published><updated>2009-08-31T22:50:31.701-07:00</updated><title type='text'>Open source and Microsoft culture</title><content type='html'>I saw this blog post about &lt;a href="http://geekswithblogs.net/alternativedotnet/archive/2009/08/31/134405.aspx"&gt;the difference between the treatment of open source&lt;/a&gt; in the Java and Microsoft communities. I must say I see this a lot and while I see the value of the support provided by Microsoft, I really have been amazed at the degree to which the Java folks just don't even consider NOT using open source. The Oracle WebLogic Server project I'm looking at now has all kinds of open source software.&lt;br /&gt;&lt;br /&gt;I guess the thing I've realized is that even when something like Hibernate or Apache or Eclipse is released under an open source license, some of the very biggest players in the technology world have highly skilled software engineers working on the code. Not because they want to give this stuff away, but because it gives them a competitive advantage in a world where the tool you use is less important than how you use that tool.&lt;br /&gt;&lt;br /&gt;Of course this was prompted by me having to write a network trace solver using ArcObjects rather than something simpler like...say...SQL! 1,000 lines of code later and I know know which valves isolate the break in a water main. Ah, the joy of closed source! :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3131102996085923653-3985762318323451088?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/3985762318323451088/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/08/open-source-and-microsoft-culture.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/3985762318323451088'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/3985762318323451088'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/08/open-source-and-microsoft-culture.html' title='Open source and Microsoft culture'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-3477122974684607545</id><published>2009-08-12T10:01:00.001-07:00</published><updated>2009-10-03T22:47:32.132-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><category scheme='http://www.blogger.com/atom/ns#' term='nunit'/><title type='text'>When you expect an exception in NUnit 2.5</title><content type='html'>&lt;p&gt;I keep forgetting this and it's a hassle to find an example. I have a piece of code that I know throws an exception during testing, but I need to then do some work after the exception has been thrown to make sure that my system is in a consistent state. Here's how I'm running some code to do the setup and throwing the actual exception. And then there's the part that does my second round of checking. Obviously in this case I don't want to see data in the database if an exception happening before my transaction was committed.&lt;/p&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/201177.js"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3131102996085923653-3477122974684607545?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/3477122974684607545/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/08/when-you-expect-exception-in-nunit-25.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/3477122974684607545'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/3477122974684607545'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/08/when-you-expect-exception-in-nunit-25.html' title='When you expect an exception in NUnit 2.5'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-653460611176285609</id><published>2009-08-03T21:18:00.001-07:00</published><updated>2009-08-03T21:18:06.297-07:00</updated><title type='text'>Event Driven Architecture</title><content type='html'>Really interesting ideas that reflect my own current thinking on system architecture. Mostly because I've been looking at this guy's work and Udi Dahan's (The Software Simplist and author of NServiceBus).&lt;div style="width:425px;text-align:left" id="__ss_1751555"&gt;&lt;a style="font:14px Helvetica,Arial,Sans-serif;display:block;margin:12px 0 3px 0;text-decoration:underline;" href="http://www.slideshare.net/PhatBoyG/event-driven-architecture" title="Event Driven Architecture"&gt;Event Driven Architecture&lt;/a&gt;&lt;object style="margin:0px" width="425" height="355"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=eventdrivenarchitecture2-090721235300-phpapp02&amp;stripped_title=event-driven-architecture" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=eventdrivenarchitecture2-090721235300-phpapp02&amp;stripped_title=event-driven-architecture" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div style="font-size:11px;font-family:tahoma,arial;height:26px;padding-top:2px;"&gt;View more &lt;a style="text-decoration:underline;" href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a style="text-decoration:underline;" href="http://www.slideshare.net/PhatBoyG"&gt;Chris Patterson&lt;/a&gt;.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3131102996085923653-653460611176285609?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/653460611176285609/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/08/event-driven-architecture.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/653460611176285609'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/653460611176285609'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/08/event-driven-architecture.html' title='Event Driven Architecture'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-192010408908040954</id><published>2009-05-20T06:44:00.001-07:00</published><updated>2009-10-03T22:49:01.501-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='oracle'/><title type='text'>Using Python and Oracle with cx_Python</title><content type='html'>&lt;h1&gt;&lt;/h1&gt;  &lt;p&gt;I needed to process records in a table with 14.4 million records the other day. The database is on my laptop so performance on a table that large sucks – no matter how many indexes you throw at the thing, it’s still all in one data file on one disk and has only 1GB of RAM to work with. My friendly DBA helped me to eliminate the big bottlenecks that I &lt;em&gt;could &lt;/em&gt;remove on a laptop, namely to increase the amount of memory assigned to client side SQL manipulation. Other than that it still crawled and then I realized that the Java functions I am calling in the update statements are the slow point, not Oracle itself. See, for each row I am doing a bunch of string manipulation related to turned crummy address data in to nice clean US Postal Service standard addresses, and that takes Java some time; not much time but enough to build up over 14.4 million iterations. And what eventually dawned on me was the JVM itself was getting bogged down and there wasn’t much I could do about it.&lt;/p&gt;  &lt;p&gt;Or was there? Again with the help of my DBA, the approach taken was to batch the rows by some arbitrary subset to reduce the load on the JVM and give it a chance to catch up. I chose rip through a ZIP codes’ worth of data for each batch and those ZIPs live in a text file. Could I have written this in PL/SQL? Maybe, but I don’t know it well enough to be productive quickly so instead I reached for my new scripting tool of choice that seems to get this type of job done quickly: Python. I got the &lt;a href="http://www.oracle.com/technology/pub/articles/prez-python-queries.html"&gt;approved&lt;/a&gt; Oracle connection bits called &lt;a href="http://cx-oracle.sourceforge.net/"&gt;cx_Oracle&lt;/a&gt; and installed them locally. I have a full Oracle install including TNS listener and database server so I didn’t have to mess with Oracle Instant Client, so here is the sum total of my code:&lt;/p&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/201178.js"&gt;&lt;/script&gt;&lt;br /&gt;&lt;p&gt;As you can see from the __main__ method at the bottom, I read in the ZIPs from a text file and eliminate duplicates, then run a couple of update statements using the current ZIP to filter my working set. Look carefully at the update statements and you can see the Java functions being called. Again, I’m sure this could easily be done in PL/SQL if you know how but I’m recording this approach here for posterity. It works. That’s good enough for me.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3131102996085923653-192010408908040954?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/192010408908040954/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/05/using-python-and-oracle-with-cxpython.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/192010408908040954'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/192010408908040954'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/05/using-python-and-oracle-with-cxpython.html' title='Using Python and Oracle with cx_Python'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-8152638154296419329</id><published>2009-05-06T15:17:00.001-07:00</published><updated>2009-05-06T18:56:41.812-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>Writing Documentation Using reStructured Text</title><content type='html'>&lt;p&gt;I’ve been working on some documentation for a web application this week. I’m not a big proponent of doing this in Microsoft Word because the docs need to be in both HTML and PDF formats for the client. Plus Word tends to get pretty squirrely when it comes to precise formatting and doing what I want vs. what it thinks I want. Think about the need to do code listings: in Word I can define a style that gives it the right font, the right indentation, and all the other stuff to make a code listing just like the examples I use in this blog. In HTML I do something similar but use CSS and the &amp;lt;pre&amp;gt; tag, with similar results. Of course the issue is that Word all too frequently mixes up the format of the surrounding paragraph and elements with my style. Just remember for a second how many times you’ve had to mess about with the indentation of the &lt;em&gt;second &lt;/em&gt;paragraph of text in a bullet? Too many.&lt;/p&gt;  &lt;p&gt;Of course, I also don’t really want to write a boat load of documentation in HTML – I’ve done it quite recently and it’s not fun, even with &lt;a href="http://www.intype.info"&gt;a great HTML editor&lt;/a&gt; to lean on. What to do? Well, I looked on the internet tubes for possible answers to my requirements:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;I want to have output in HTML and PDF &lt;/li&gt;    &lt;li&gt;It needs to support version control in a friendly way, so text-based files are a bonus and binary files are a no-no &lt;/li&gt;    &lt;li&gt;Non-technical (non-developer) people should be able to write the help files without needing more than a little bit of training and a text editor. &lt;/li&gt;    &lt;li&gt;It needs to be free - &lt;a href="http://www.adobe.com/products/robohelp/"&gt;Adobe's RoboHelp&lt;/a&gt; does this stuff but it costs $999. Obviously not going to work for me no matter how cool it is. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;I quickly came across one documentation tool that does what I need: &lt;a href="http://sphinx.pocoo.org/index.html"&gt;the Sphinx&lt;/a&gt; Python documentation generator. “Huh?” I hear you say, “&lt;em&gt;Python&lt;/em&gt; document generator…how the heck does that fit your list of requirements?” Well, the interesting thing about Sphinx is that it uses a very simple text format called &lt;a href="http://docutils.sourceforge.net/rst.html"&gt;reStructured Text&lt;/a&gt; (reST) that lets you write simple markup that mostly looks like simple text without a ton of angle brackets (like &amp;lt;em&amp;gt;hello&amp;lt;/em&amp;gt;). Sphinx then runs a process using the Python &lt;a href="http://docutils.sourceforge.net/index.html"&gt;docutils&lt;/a&gt; utilities that turns the reST in to other formats like HTML and LaTeX. Yes, the whole purpose of Sphinx is to convert reST into &lt;em&gt;exactly the formats I need!&lt;/em&gt; From the reST page:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;“Docutils is an open-source text processing system for processing plaintext documentation into useful formats, such as HTML or LaTeX. It includes &lt;a href="http://docutils.sourceforge.net/rst.html"&gt;reStructuredText&lt;/a&gt;, the easy to read, easy to use, what-you-see-is-what-you-get plaintext markup language.”&lt;/p&gt; &lt;/blockquote&gt; &lt;p&gt;So it turns out that docutils and Sphinx come from a Python heritage and are implemented using Python, but they are generic tools that can be used to generate any kind of documentation you want using reST. Which sounds like exactly what I’m looking for.&lt;/p&gt;  &lt;h4&gt;reStructured Text&lt;/h4&gt; &lt;p&gt;Rather than rehash all of the bells and whistles in reST I thought I’d just post an example:&lt;/p&gt; &lt;pre class="brush: plain; ruler: true; gutter: false; toolbar: false;"&gt;============&lt;br /&gt;Introduction&lt;br /&gt;============&lt;br /&gt;&lt;br /&gt;The :abbr:`EMMA (Election Map Maintenance Application)` application enables election officials at multiple levels of government stay on top of changes in electoral boundaries. Specifically it is designed to support changes to precinct boundaries across the entire state of Ohio. Election officials at the county level can propose modifications to precincts that adhere to U.S. Census and |ohsos| rules, and then |ohsos| staff can take those modifications through an electronic approval process. The benefit of EMMA is the easy management of what can quickly become complex changes, and a good historical record of all proposed changes whether or not they eventually are accepted.&lt;br /&gt;&lt;br /&gt;.. warning:: This is a warning.&lt;br /&gt;&lt;br /&gt;.. note:: This is a note.&lt;br /&gt;&lt;br /&gt;.. sidebar:: A sidebar&lt;br /&gt;&lt;br /&gt;    with some content&lt;br /&gt;&lt;br /&gt;Before diving in to the detailed workflow guides or specific tool descriptions, take a look at the glossary to make sure you understand the various terms that are used throughout this documentation. While many of them, such as *precinct*, may be familiar to you, others such as :term:`VTD` and :term:`TIGER` may not.&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;You can see that a couple of simple conventions like indentation and blank lines are used to give the document its structure. Also the main heading just has some lines around it to make it stand out. What else?&lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;  &lt;li&gt;Directives — see the &lt;code&gt;.. warning::&lt;/code&gt; and the &lt;code&gt;.. sidebar::&lt;/code&gt;? Those are simple tags that represent semantic parts of the document. I don't even really need to describe what they are. &lt;/li&gt;&lt;br /&gt;  &lt;li&gt;:term:`VTD` — This is a reference to a definition. Elsewhere in my reST document(s) I have a &lt;code&gt;.. glossary::&lt;/code&gt; directive which has the description of what VTD actually is. reST is smart enough to link the two. &lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;But the really great part is the reST is semantic – it describes the content and structure of my document in a way that HTML and Word &lt;em&gt;should &lt;/em&gt;but often don’t. Way too much time worrying about the colors, the indentations, and all that other guff.&lt;/p&gt;&lt;br /&gt;&lt;h4&gt;Generating Output&lt;/h4&gt;&lt;br /&gt;&lt;p&gt;Yeah, yeah, so semantic content and structure are great concepts, but how does that help me achieve my goal. Well Sphinx has utilities to take the reST and output in a variety of formats. Actually I think the only two widely used formats are HTML and LaTeX. If you haven’t come across LaTeX before then you owe it to yourself to do &lt;a href="http://www.latex-project.org/"&gt;a little&lt;/a&gt;&amp;#160;&lt;a href="http://en.wikipedia.org/wiki/LaTeX"&gt;research&lt;/a&gt;. The short version is that it is also a text-based way to describe typeset quality documents (think magazines, journals, documentation) plus tools to take those LaTeX documents and convert them to formats like PDF. Aha! Now you’re getting the point here. In a nutshell:&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Write reST documents in simple markup&lt;br/&gt;&lt;br /&gt;→ Run reST files through Sphinx&lt;br/&gt;&lt;br /&gt;→ Sphinx produces HTML or LaTeX&lt;br/&gt;&lt;br /&gt;→ For LaTeX, turn the TEX file in to PDF&lt;br/&gt;&lt;br /&gt;The “Run reST files through Sphinx” part is straightforward. In fact Sphinx has a handy command to run that even creates a little batch file to help you do it:&lt;/p&gt;&lt;br /&gt;&lt;pre class="brush: bash; ruler: true; gutter: false; toolbar: false;"&gt;make html&lt;br /&gt;make latex&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;As long as Python is installed with the Sphinx and docutils bits, that is all you need to do for HTML. For LaTeX → PDF conversion you also need to have a LaTeX processor. I am using a distribution called &lt;a href="http://miktex.org/"&gt;MiKTeX&lt;/a&gt; that runs very well on Windows and gives me another simple one liner:&lt;/p&gt;&lt;br /&gt;&lt;pre class="brush: bash; ruler: true; gutter: false; toolbar: false;"&gt;pdflatext SphinxOutput.tex&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;The result is a very professional looking version of the documentation in PDF. The great part is that the glossary of terms is still all hyperlinked within the document, as are the table of contents and index. Sweet.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_-FppOh0pKM8/SgIMdO1H9gI/AAAAAAAAEG4/UuRE9nvhTyI/s1600-h/5-6-2009%203-07-26%20PM%5B3%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="5-6-2009 3-07-26 PM" border="0" alt="5-6-2009 3-07-26 PM" src="http://lh3.ggpht.com/_-FppOh0pKM8/SgIMeTqH50I/AAAAAAAAEG8/o0DkYZZn6uw/5-6-2009%203-07-26%20PM_thumb%5B1%5D.png?imgmax=800" width="812" height="399" /&gt;&lt;/a&gt;&amp;#160;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The PDF output for the glossary. In the HTML this is a Definition List.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_-FppOh0pKM8/SgIMelF6r7I/AAAAAAAAEHA/su6Y36bWGQ4/s1600-h/5-6-2009%203-10-18%20PM%5B3%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="5-6-2009 3-10-18 PM" border="0" alt="5-6-2009 3-10-18 PM" src="http://lh4.ggpht.com/_-FppOh0pKM8/SgIMezh2pWI/AAAAAAAAEHE/AFsEbksCWq8/5-6-2009%203-10-18%20PM_thumb%5B1%5D.png?imgmax=800" width="632" height="369" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;br /&gt;&lt;p&gt;Here’s the proof that references and content structure turns in to something useful in the PDF&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_-FppOh0pKM8/SgIMfaOUlaI/AAAAAAAAEHI/4vROej7E6ZA/s1600-h/5-6-2009%203-10-55%20PM%5B2%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="5-6-2009 3-10-55 PM" border="0" alt="5-6-2009 3-10-55 PM" src="http://lh3.ggpht.com/_-FppOh0pKM8/SgIMf7QtesI/AAAAAAAAEHM/8zx6NH41H-Q/5-6-2009%203-10-55%20PM_thumb.png?imgmax=800" width="183" height="150" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;br /&gt;&lt;h4&gt;A Bit More Detail on Requirements&lt;/h4&gt;&lt;br /&gt;&lt;p&gt;Because it took a little preparation to get up and running, I’ll share a quick README that I wrote myself so that I can remember how this works. Here you go:&lt;/p&gt;&lt;br /&gt;&lt;pre class="brush: plain; ruler: true; gutter: false; toolbar: false;"&gt;Setup&lt;br /&gt;=====&lt;br /&gt;Building this documentation requires the following to be installed&lt;br /&gt;on your system:&lt;br /&gt;&lt;br /&gt;* Python 2.5.4&lt;br /&gt;    * download from http://www.python.org/download/&lt;br /&gt;    * Add the C:\Python25 directory to your Windows PATH&lt;br /&gt;* EasyInstall&lt;br /&gt;    * run setuptools-0.6c9.win32-py2.5.exe found in the same&lt;br /&gt;      directory as this readme file&lt;br /&gt;    * Add C:\Python25\Scripts to your Windows PATH&lt;br /&gt;* Sphinx documentation tools&lt;br /&gt;    * Open a command prompt and go to Project\docs\manual&lt;br /&gt;    * Type 'easy_install Sphinx' from a command prompt, making sure&lt;br /&gt;      that you have an active Internet connection to download dependencies&lt;br /&gt;* MikTex - LaTeX/PDF document generator&lt;br /&gt;    * Download the Basic MiKTeX 2.7 installer from http://miktex.org/2.7/setup&lt;br /&gt;&lt;br /&gt;Building the documentation:&lt;br /&gt;===========================&lt;br /&gt;* Open a command prompt and cd to Project\doc\manual&lt;br /&gt;* HTML version&lt;br /&gt;    * type 'make html'&lt;br /&gt;    * look in manual\build\html&lt;br /&gt;* PDF version&lt;br /&gt;    * type 'make latex'&lt;br /&gt;    * cd build\latex&lt;br /&gt;    * type 'pdflatex mydocs.tex' - NOTE: If you are asked to download additional&lt;br /&gt;      components during the first run then say YES! MiKTeX needs some extra bits&lt;br /&gt;      to support the features required by the Sphinx PDF documentation style.&lt;br /&gt;    * look for the mydocs.pdf&lt;br /&gt;    * If the Table of Context is not showing up in the PDF simply rerun the pdflatex&lt;br /&gt;      command. That usually fixes it.&lt;br /&gt;&lt;br /&gt;If you need to clean up and start from scratch:&lt;br /&gt;* type 'make clean'&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Gotchas&lt;/h4&gt;&lt;br /&gt;&lt;p&gt;Of course the world is not perfect. Configuring the documentation build happens in a python file called conf.py. I have yet to see much of how the LaTeX output can be configured beyond a handful of modifications. This is turn means that the PDF layout is largely beyond my control unless I want to get my hands dirty with the tex file itself. Which I don’t! Also, to change the layout of the HTML beyond the simple cosmetics would mean getting in to the Sphinx templating approach (which is similar to Django templates but not worth it for my current project).&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3131102996085923653-8152638154296419329?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/8152638154296419329/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/05/writing-documentation-using.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/8152638154296419329'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/8152638154296419329'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/05/writing-documentation-using.html' title='Writing Documentation Using reStructured Text'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_-FppOh0pKM8/SgIMeTqH50I/AAAAAAAAEG8/o0DkYZZn6uw/s72-c/5-6-2009%203-07-26%20PM_thumb%5B1%5D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-3913980904409561684</id><published>2009-05-04T21:08:00.001-07:00</published><updated>2009-05-06T18:58:36.201-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='automation'/><category scheme='http://www.blogger.com/atom/ns#' term='utility'/><category scheme='http://www.blogger.com/atom/ns#' term='oracle'/><title type='text'>Talking to Oracle with Ant</title><content type='html'>&lt;p&gt;I’m working on my first Java project this month and wanted to automate some PL/SQL scripts. They do a bunch of setup and teardown on a local Oracle instance to get it ready for work. I’ll soon be adding a simpler task for pushing some disposable test data in to the same database, but for now I’ll keep it simple. Anyway, on .NET projects I like to use msbuild to get my initial post-subversion checkout environment all squared away. Here’s my first Ant build script to handle a little Oracle. Of course you can see that it’s not exactly rocket science. A little Googling got me on the right path, and I feel immediately more at home with this format than I did when starting MSBuild. I guess maybe I should have tried NAnt!&lt;/p&gt;&lt;pre class="brush: xml; ruler: true; gutter: false; toolbar: false;"&gt;&amp;lt;?xml version="1.0" encoding="windows-1252" ?&amp;gt;&lt;br /&gt;&amp;lt;project default="init" basedir="../../"&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;!-- Assumes the existence of a build properties file --&amp;gt;&lt;br /&gt;    &amp;lt;property file="${basedir}/override.properties"/&amp;gt;&lt;br /&gt;    &amp;lt;property file="${basedir}/build.properties"/&amp;gt;&lt;br /&gt;           &lt;br /&gt;    &amp;lt;target name="init"&amp;gt;&amp;lt;/target&amp;gt;&lt;br /&gt;    &lt;br /&gt;    &amp;lt;!-- Rebuild derived (non-census) data from scratch --&amp;gt;&lt;br /&gt;    &amp;lt;target name="tiger.db.up" depends="tiger.db.down"&amp;gt;&lt;br /&gt;        &amp;lt;exec executable="${db.sqlplus}" dir="${project.persistence}/sql/tiger"&amp;gt;&lt;br /&gt;            &amp;lt;arg line="${db.sqlplus.sys} @doall.sql"/&amp;gt;&lt;br /&gt;        &amp;lt;/exec&amp;gt;&lt;br /&gt;    &amp;lt;/target&amp;gt;&lt;br /&gt;    &lt;br /&gt;     &amp;lt;!-- Drop any objects not coming directly from census, i.e., derived data --&amp;gt;&lt;br /&gt;    &amp;lt;target name="tiger.db.down"&amp;gt;&lt;br /&gt;        &amp;lt;exec executable="${db.sqlplus}" dir="${project.persistence}/sql/tiger"&amp;gt;&lt;br /&gt;            &amp;lt;arg line="${db.sqlplus.sys} @dropall.sql"/&amp;gt;&lt;br /&gt;        &amp;lt;/exec&amp;gt;&lt;br /&gt;    &amp;lt;/target&amp;gt;&lt;br /&gt;    &lt;br /&gt;&lt;br /&gt;&amp;lt;/project&amp;gt;&lt;/pre&gt;&lt;br /&gt;The basedir property simply points to a directory two levels up. Why? Because I have a few standard properties that developers will need in order for the build to work. The neat part is that they can also create an override.properties file to, well, override (!) any of the defaults that they want to, e.g., the name of the Oracle instance, a username, whatever. Note that the references to the property files in my example above are in a particular order; properties in Ant are immutable so once I’ve defined it in my override file, it cannot then be redefined in the build.properties file even if it’s listed there. Nice and simple. Here’s the build.properties and my override.&lt;pre class="brush: plain; ruler: true; gutter: false; toolbar: false;"&gt;&amp;lt;pre&amp;gt;#If you need to override any of these properties, create an &lt;br /&gt;# override.properties file in the same folder and make sure&lt;br /&gt;# that it is imported FIRST in any build scripts.&lt;br /&gt;&lt;br /&gt;# Oracle server and connection info&lt;br /&gt;# Note that the $ is escaped with a leading $, so $$$$ equates to $$&lt;br /&gt;db.sys.password = pa$$$$w0rd&lt;br /&gt;db.sqlplus = sqlplus&lt;br /&gt;db.host = yadda.yadda.whatever.com&lt;br /&gt;db.sid = yomamma&lt;br /&gt;db.sqlplus.sys = sys/${db.sys.password} as sysdba@//${db.host}/${db.sid}&lt;br /&gt;&lt;br /&gt;tiger.state.user = tiger2007_39&lt;br /&gt;tiger.state.password = tiger2007_39&lt;br /&gt;&lt;br /&gt;# Project directories&lt;br /&gt;# base.dir is defined in each build script and describes&lt;br /&gt;# the relationship between the build.xml location and&lt;br /&gt;# the relative location of all of the project&lt;br /&gt;# directories. For example, if an Ant file is located&lt;br /&gt;# in SomeCommon\ant\build.xml then the base.dir value&lt;br /&gt;# defined in that file might read "../../" meaning that&lt;br /&gt;# the project directories are "two levels up from me"&lt;br /&gt;some.common = ${basedir}/SomeCommon&lt;br /&gt;some.persistence = ${basedir}/SomePersistence&lt;br /&gt;some.security = ${basedir}/SomeSecurity&lt;br /&gt;&lt;br /&gt;# WARNING: Make sure that you leave an EMPTY LINE at the end of this file.&lt;/pre&gt;And the override. Notice I just need to override a couple of properties: the rest are left untouched.&lt;pre&gt;&lt;/pre&gt;&lt;pre class="brush: plain; ruler: true; gutter: false; toolbar: false;"&gt;# Any values added here will override values&lt;br /&gt;# that exist in build.properties. If a value&lt;br /&gt;# is not present here the value from build.properties&lt;br /&gt;# will be used by default.&lt;br /&gt;db.sys.password = secret.word&lt;br /&gt;db.host = my.pc.com&lt;br /&gt;db.sid = oracle&lt;/pre&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3131102996085923653-3913980904409561684?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/3913980904409561684/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/05/talking-to-oracle-with-ant.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/3913980904409561684'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/3913980904409561684'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/05/talking-to-oracle-with-ant.html' title='Talking to Oracle with Ant'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-8920148868791752118</id><published>2009-04-18T09:13:00.001-07:00</published><updated>2009-05-06T18:57:31.360-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='offtopic'/><title type='text'>On Visualization</title><content type='html'>&lt;p&gt;I'm rereading &lt;a href="http://www.amazon.com/Genius-Life-Science-Richard-Feynman/dp/0679747044" target="_blank"&gt;Genius: The Life and Science of Richard Feynman&lt;/a&gt; by James Gleick this&amp;#160; &lt;a href="http://lh3.ggpht.com/_-FppOh0pKM8/Sen8JIQxNgI/AAAAAAAAEFQ/EUWFjttFufg/s1600-h/genius%5B4%5D.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; margin-left: 0px; border-left-width: 0px; margin-right: 0px" title="genius" border="0" alt="genius" align="right" src="http://lh6.ggpht.com/_-FppOh0pKM8/Sen8JS-_oDI/AAAAAAAAEFU/r1wi8R6WpdE/genius_thumb%5B5%5D.jpg?imgmax=800" width="80" height="119" /&gt;&lt;/a&gt; week. Incidentally he’s written another one of my favorite books, &lt;a href="http://www.amazon.com/Chaos-Making-Science-James-Gleick/dp/0143113453/ref=pd_lpo_k2_dp_k2a_2_txt?pf_rd_p=304485601&amp;amp;pf_rd_s=lpo-top-stripe-2&amp;amp;pf_rd_t=201&amp;amp;pf_rd_i=0140092501&amp;amp;pf_rd_m=ATVPDKIKX0DER&amp;amp;pf_rd_r=15DPBWNCVV686K13DHDY" target="_blank"&gt;Chaos: Making a New Science&lt;/a&gt; which was originally written in 1988 and just republished last year. If you enjoy popular science writing Chaos is a great read. Anyway, back to Genius.&lt;/p&gt;  &lt;p&gt;One of the things I frequently find myself doing when I’m at the early stages of a software development project is staring at the wall for an hour at a time. Literally an hour plus. I read up on the “literature” which entails a ton of blog posts, maybe some best practices described by the software vendor or open source folks that who’s package I’m using, and then talking with my colleagues. After that research I try to internalize what goals the software has to achieve and then the wall-staring begins. If I were to try to describe what I “see”, it’s like a collection of boxes of different colors floating around and forming connections with each other. The connections have different thicknesses and sort of pulsate with light when I feel there’s a good link between two things, or when there are signals or messages between them. Finally, as things settle down and I get closer to a starting point (where I could write a little code) the boxes start to crystallize like the water-to-ice phase transition and a more rigid structure emerges. And then I crack open my coding tool and start typing frantically before I forget what I just thought out…only to discover it was crap and I begin the process again but with a slightly different set of beginning assumptions.&lt;/p&gt;  &lt;p&gt;Can you believe what I do for a living? :-)&lt;/p&gt;  &lt;p&gt;Anyway, I am always interested to hear how other people deal with this visualization issue for things that don’t really have a physical, visual representation. This morning I re-read a great quotation of Feynman, the Nobel winning theoretical physicist and bongo drum player as he attempts to describe his approach to visualizing the impossible:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;“What I am really trying to do is being birth to clarity, which is really a half-assedly thought-out pictorial semi-vision thing. I would see the jiggle-jiggle or the wiggle of the path. Even now when I talk about the influence functional, I see the coupling and I take this turn—like as if there was a big bag of stuff—and try to collect it away and to push it. It’s all visual. It’s hard to explain.”&lt;/p&gt;    &lt;p align="right"&gt;Chaos, p 244&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Isn’t that just the best description ever of a visual thought process? It completely captures the indescribable nature of how we intuitive think about complex processes that really are difficult to describe. For a physicist it’s the way that you think about E- and B-fields and electron paths; for software developers it’s the admittedly much easier design process. The end result is something concrete: a set of equations or a class diagram which are blueprints for reproducing what’s going on inside our heads. But what I love about it is the leveling of the playing field because I think all of us go through the visualization process when we’re working on something that is hard to put down on paper until we have the final answer.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3131102996085923653-8920148868791752118?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/8920148868791752118/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/04/on-visualization.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/8920148868791752118'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/8920148868791752118'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/04/on-visualization.html' title='On Visualization'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/_-FppOh0pKM8/Sen8JS-_oDI/AAAAAAAAEFU/r1wi8R6WpdE/s72-c/genius_thumb%5B5%5D.jpg?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-753233824146951431</id><published>2009-04-17T16:45:00.001-07:00</published><updated>2009-10-03T22:55:31.480-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><title type='text'>How to get the display name of a Windows login when you start from the login name</title><content type='html'>&lt;p&gt;I was surprised how complicated this is, but upon reflection it is just because I have never used LDAP or Active Directory before. Basically I have an ASP.NET Web Form and access to the currently-connected user, looking something like this: DOMAIN\doe32. I need to get the display name associated with that user, e.g., “John Doe”. Here’s one solution:&lt;/p&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/201181.js"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3131102996085923653-753233824146951431?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/753233824146951431/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/04/how-to-get-display-name-of-windows.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/753233824146951431'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/753233824146951431'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/04/how-to-get-display-name-of-windows.html' title='How to get the display name of a Windows login when you start from the login name'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-1494785972070458192</id><published>2009-01-26T15:08:00.001-08:00</published><updated>2009-10-03T22:58:51.647-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><category scheme='http://www.blogger.com/atom/ns#' term='utility'/><title type='text'>Utility Function for Creating Images on the Fly</title><content type='html'>&lt;p&gt;Really goofy, but I keep this handy for created files on the fly, especially when I’m testing system boundaries for files of various sizes. For example, in my current project I limited the size of an upload to 5MB – so I create a whopping big image on the fly then try to send it.&lt;/p&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/201182.js"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3131102996085923653-1494785972070458192?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/1494785972070458192/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/01/utility-function-for-creating-images-on.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/1494785972070458192'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/1494785972070458192'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/01/utility-function-for-creating-images-on.html' title='Utility Function for Creating Images on the Fly'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-7109246948043247536</id><published>2009-01-06T20:17:00.001-08:00</published><updated>2009-11-20T16:22:51.866-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><category scheme='http://www.blogger.com/atom/ns#' term='utility'/><title type='text'>Compression using 7zip and .NET</title><content type='html'>&lt;p&gt;I needed to compress some data across the wire on a project. Basically sending very large files that, when compressed, get really small so choosing the right compression algorithm is important. I ran tests with SharpZipLib and the native .NET zip compression handlers with decent results. But I also use the &lt;a target="_blank" href="http://www.7-zip.org/"&gt;7-zip&lt;/a&gt; desktop application for my day to day usage instead of WinZip so I tried compressing the data files using that as well. Glad I did – the 7-zip compressed an additional 20% on top of what ZIP did. Well worth the effort to incorporate in to my WCF application.&lt;/p&gt;  &lt;p&gt;I basically took the code wholesale from &lt;a target="_blank" href="http://geekswithblogs.net/robz/archive/2008/09/23/sharpziplib-versus-7-zip-for-large-file-sets.aspx"&gt;this post by Rob Reynolds&lt;/a&gt; and sprinkled in a little of my own meager magic. The solution revolves around a generic IZip interface and IZipFileUtility. Lot’s of comments:&lt;/p&gt;&lt;script src="http://gist.github.com/239899.js"&gt;&lt;/script&gt;&lt;p&gt;The SevenZip implementation essentially calls the command line version of the 7-zip utility (7za.exe) with the appropriate parameters:&lt;/p&gt;&lt;script src="http://gist.github.com/239906.js"&gt;&lt;/script&gt;&lt;p&gt;And of course the concrete implementation of the IFileZipUtility actually pulls it all together. The idea is that this could have a WinZip implementation as well if necessary so that there would be no non-Base Class Library dependencies. You can see this &lt;a href="http://dylansknowledgebase.googlecode.com/svn/Compression/source/Woolpert.Compression/FileZipUtility.cs"&gt;in the Subversion repository&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Here’s how it looks in a test case:&lt;/p&gt;&lt;script src="http://gist.github.com/239909.js?file=ZipTest.cs"&gt;&lt;/script&gt;&lt;p&gt;You can grab all of the source code from &lt;a target="_blank" href="http://code.google.com/p/dylansknowledgebase/source/browse/Compression/"&gt;Google Code&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/3131102996085923653-7109246948043247536?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/7109246948043247536/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/01/compression-using-7zip-and-net.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/7109246948043247536'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/7109246948043247536'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/01/compression-using-7zip-and-net.html' title='Compression using 7zip and .NET'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-8006374227666989387</id><published>2009-01-05T17:00:00.001-08:00</published><updated>2009-01-05T17:00:51.222-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><title type='text'>Parsing XML in a SQL Server Stored Procedure</title><content type='html'>&lt;p&gt;I had to send a variable number of columns and values to a stored procedure. So for one query I might need to do the equivalent of an IN query (all values in one search column), but in other cases I might need to do a search on a number of columns and values (WHERE a = 1 AND b = 2 OR…).&lt;/p&gt;  &lt;p&gt;There are all kinds of ways of doing this, but for my application I opted to create a little XML snippet to send the data. Don’t ask me why except that it makes a lot of sense in the context of the code I need to execute.&lt;/p&gt;  &lt;p&gt;Here’s the C# code where I’m calling my procedure:&lt;/p&gt;  &lt;p&gt;&lt;textarea class="c#" name="code"&gt;using (var repository = new RepositoryBase(this._connectionStringName))&amp;lt;br /&amp;gt;{&amp;lt;br /&amp;gt; IDbCommand command = new SqlCommand(storedProcedure) { CommandType = CommandType.StoredProcedure };&amp;lt;br /&amp;gt; IDbDataParameter p = command.CreateParameter();&amp;lt;br /&amp;gt; p.DbType = DbType.Xml;&amp;lt;br /&amp;gt; p.ParameterName = &amp;quot;?list&amp;quot;;&amp;lt;br /&amp;gt; p.Direction = ParameterDirection.Input;&amp;lt;br /&amp;gt; p.Value = auditTracking.GenerateCoreEditListAsXml().ToString(SaveOptions.None);&amp;lt;br /&amp;gt; command.Parameters.Add(p);&amp;lt;br /&amp;gt; DataSet edits = repository.ExecuteQuery(command, tableNames);&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt; affectedRecords = this.ParseResultsToAuditRecords(edits);&amp;lt;br /&amp;gt;}&lt;/textarea&gt;&lt;/p&gt;  &lt;p&gt;Where the GenerateCoreEditListAsXml function sets the value of the p.Value parameter to something like this:&lt;/p&gt;  &lt;p&gt;&lt;textarea class="xml" name="code"&gt;&amp;lt;PKs&amp;gt;&amp;lt;br /&amp;gt; &amp;lt;row id=&amp;quot;1&amp;quot;&amp;gt;&amp;lt;br /&amp;gt; &amp;lt;pk name=&amp;quot;FCA_SURVEY_ID&amp;quot;&amp;gt;35255&amp;lt;/pk&amp;gt;&amp;lt;br /&amp;gt; &amp;lt;/row&amp;gt;&amp;lt;br /&amp;gt; &amp;lt;row id=&amp;quot;2&amp;quot;&amp;gt;&amp;lt;br /&amp;gt; &amp;lt;pk name=&amp;quot;FCA_SURVEY_ID&amp;quot;&amp;gt;35254&amp;lt;/pk&amp;gt;&amp;lt;br /&amp;gt; &amp;lt;/row&amp;gt;&amp;lt;br /&amp;gt;&amp;lt;/PKs&amp;gt;&lt;/textarea&gt;&lt;/p&gt;  &lt;p&gt;In regular SQL calling the procedure looks something like this:&lt;/p&gt;  &lt;p&gt;&lt;textarea class="sql" rows="rows" name="code"&gt;use [CorridorField]&amp;lt;br /&amp;gt;declare @list xml;&amp;lt;br /&amp;gt;set @list = '&amp;lt;PKs&amp;gt;&amp;lt;br /&amp;gt; &amp;lt;row id=&amp;quot;1&amp;quot;&amp;gt;&amp;lt;br /&amp;gt; &amp;lt;pk name=&amp;quot;PATH_ID&amp;quot;&amp;gt;10&amp;lt;/pk&amp;gt;&amp;lt;br /&amp;gt; &amp;lt;pk name=&amp;quot;ATTRIB_NAME&amp;quot;&amp;gt;_Last Visit&amp;lt;/pk&amp;gt;&amp;lt;br /&amp;gt; &amp;lt;pk name=&amp;quot;ATTRIB_VALUE&amp;quot;&amp;gt;20-Jun-2005&amp;lt;/pk&amp;gt;&amp;lt;br /&amp;gt; &amp;lt;/row&amp;gt;&amp;lt;br /&amp;gt; &amp;lt;row id=&amp;quot;2&amp;quot;&amp;gt;&amp;lt;br /&amp;gt; &amp;lt;pk name=&amp;quot;PATH_ID&amp;quot;&amp;gt;10&amp;lt;/pk&amp;gt;&amp;lt;br /&amp;gt; &amp;lt;pk name=&amp;quot;ATTRIB_NAME&amp;quot;&amp;gt;05. Service&amp;lt;/pk&amp;gt;&amp;lt;br /&amp;gt; &amp;lt;pk name=&amp;quot;ATTRIB_VALUE&amp;quot;&amp;gt;Air Force&amp;lt;/pk&amp;gt;&amp;lt;br /&amp;gt; &amp;lt;/row&amp;gt;&amp;lt;br /&amp;gt; &amp;lt;row id=&amp;quot;3&amp;quot;&amp;gt;&amp;lt;br /&amp;gt; &amp;lt;pk name=&amp;quot;PATH_ID&amp;quot;&amp;gt;12&amp;lt;/pk&amp;gt;&amp;lt;br /&amp;gt; &amp;lt;pk name=&amp;quot;ATTRIB_NAME&amp;quot;&amp;gt;_Playground PA&amp;lt;/pk&amp;gt;&amp;lt;br /&amp;gt; &amp;lt;pk name=&amp;quot;ATTRIB_VALUE&amp;quot;&amp;gt;Yes&amp;lt;/pk&amp;gt;&amp;lt;br /&amp;gt; &amp;lt;/row&amp;gt;&amp;lt;br /&amp;gt;&amp;lt;/PKs&amp;gt;'&amp;lt;br /&amp;gt;DECLARE @RC int&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;EXECUTE @RC = [CorridorField].[FCA].[uspAuditPath_Attrib] &amp;lt;br /&amp;gt; @list&lt;/textarea&gt;&lt;/p&gt;  &lt;p&gt;The procedure I’m calling in turn has this inside it. Notice how I’m first transforming the XML parameter in to a temporary table? That is so I can use it as the filter on the WHERE portion of the main query using an IN statement:&lt;/p&gt;  &lt;p&gt;&lt;textarea class="sql" rows="rows" name="code"&gt;set ANSI_NULLS ON&amp;lt;br /&amp;gt;set QUOTED_IDENTIFIER ON&amp;lt;br /&amp;gt;go&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;/*&amp;lt;br /&amp;gt; Get all data associated with a batch of FUS_BLDGS records&amp;lt;br /&amp;gt;*/&amp;lt;br /&amp;gt;ALTER procedure [FCA].[uspAuditPath_Attrib](@list xml)&amp;lt;br /&amp;gt;as&amp;lt;br /&amp;gt;declare @results table(PKRow varchar(30), PKColumn varchar(30), PKValue varchar(30))&amp;lt;br /&amp;gt; &amp;lt;br /&amp;gt;insert into @results&amp;lt;br /&amp;gt; select DataSource.keys.value('../@id','varchar(30)') as PKRow&amp;lt;br /&amp;gt; , DataSource.keys.value('@name','varchar(30)') as PKColumn&amp;lt;br /&amp;gt; , DataSource.keys.value('.','varchar(30)') as PKValue&amp;lt;br /&amp;gt; from @list.nodes('/PKs/row/pk') as DataSource(keys)&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;select * from @results;&amp;lt;br /&amp;gt;-- paths&amp;lt;br /&amp;gt;select distinct(p.path_id) from [path] p&amp;lt;br /&amp;gt;where convert(varchar(30),path_id) in (select distinct(convert(varchar(30),pa.path_id))&amp;lt;br /&amp;gt; from dbo.path_attrib as pa&amp;lt;br /&amp;gt; where convert(varchar(30),pa.path_id) in &amp;lt;br /&amp;gt; (select PKValue from @results))&amp;lt;br /&amp;gt;&lt;/textarea&gt;&lt;/p&gt;  &lt;p&gt;So what do the results look like? Pretty boring actually. The purpose is to pass in multiple rows with multiple discriminating columns and use those to get records from a related table. In this case it’s kind of boring but I couldn’t think of a better or more flexible way of doing it. Maybe I’m just creating a rats nest of maintenance but it’ll work for now.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_-FppOh0pKM8/SWKtPopxv-I/AAAAAAAAD4A/NF-iDh-qXlc/s1600-h/image%5B3%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/_-FppOh0pKM8/SWKtQUDUlHI/AAAAAAAAD4E/EDQCycsfYD4/image_thumb%5B1%5D.png?imgmax=800" width="282" height="345" /&gt;&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/3131102996085923653-8006374227666989387?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/8006374227666989387/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/01/parsing-xml-in-sql-server-stored.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/8006374227666989387'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/8006374227666989387'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/01/parsing-xml-in-sql-server-stored.html' title='Parsing XML in a SQL Server Stored Procedure'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_-FppOh0pKM8/SWKtQUDUlHI/AAAAAAAAD4E/EDQCycsfYD4/s72-c/image_thumb%5B1%5D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-6947469617711534147</id><published>2009-01-05T07:51:00.001-08:00</published><updated>2009-12-07T16:12:36.018-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wix'/><title type='text'>WiX and XML, Windows Services</title><content type='html'>&lt;p&gt;I was tripped up by a couple of &lt;a target="_blank" href="http://wix.sourceforge.net/"&gt;WiX&lt;/a&gt; things this week while building an installation package for a Windows services project.&lt;/p&gt;  &lt;h4&gt;Windows Services&lt;/h4&gt;  &lt;p&gt;The first was getting the Windows service to be started correctly. I’ve done this before but couldn’t get it to work this time around. Here was my starting point:&lt;/p&gt;&lt;script src="http://gist.github.com/251276.js?file=Wix-part.xml"&gt;&lt;/script&gt;&lt;p&gt;I am using a 3rd party compression tool—&lt;a target="_blank" href="http://www.7-zip.org/"&gt;7zip&lt;/a&gt;— to manage some aspects of my app so, being alphabetically inclined, I put that first on my list of files to include. The actual service is in the file FcaImportService.exe. Then I have my usual service setup and start bits in the same component like this:&lt;/p&gt;&lt;script src="http://gist.github.com/251278.js?file=wix-list.xml"&gt;&lt;/script&gt;&lt;p&gt;As I mentioned I’ve used this exact approach before with success. But that darn service kept bombing when it was trying to start! It was a really easy fix though. Simply make sure that the first File in the Component is the one that holds the service implementation and WiX will then happily create the service while pointing to the correct executable. Just look in the Service Control Manager to see which file WiX is actually pointing at:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_-FppOh0pKM8/SWIsXa8YOjI/AAAAAAAAD34/0t9CDi7eZsI/s1600-h/image%5B7%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://lh5.ggpht.com/_-FppOh0pKM8/SWIsZaSFRnI/AAAAAAAAD38/OPi6KYvZJ9E/image_thumb%5B3%5D.png?imgmax=800" width="408" height="440" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;h4&gt;XML&lt;/h4&gt;  &lt;p&gt;Really annoying one. It turns out that the Windows installer database that is encapsulated in the *.MSI file treats square brackets as variable delimeters. So when you use a string that WiX is going to interpret and that string includes square brackets, you need to escape them. Naturally one example is in XPath. Here’s how it should look in WiX:&lt;/p&gt;&lt;script src="http://gist.github.com/251281.js?file=wix-fixed.xml"&gt;&lt;/script&gt;&lt;p&gt;Hope that saves you a few minutes of head scratching.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3131102996085923653-6947469617711534147?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/6947469617711534147/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/01/wix-and-xml-windows-services.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/6947469617711534147'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/6947469617711534147'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2009/01/wix-and-xml-windows-services.html' title='WiX and XML, Windows Services'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_-FppOh0pKM8/SWIsZaSFRnI/AAAAAAAAD38/OPi6KYvZJ9E/s72-c/image_thumb%5B3%5D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-4460321188265332206</id><published>2008-12-20T10:57:00.001-08:00</published><updated>2009-10-04T19:10:09.093-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='jquery'/><category scheme='http://www.blogger.com/atom/ns#' term='asp.net'/><title type='text'>jQuery and ASP.NET Validation Controls Disagree</title><content type='html'>&lt;p&gt;I spent the better part of a morning struggling to understand how ASP.NET Validation controls interact with non-ASP.NET elements in a page.&lt;/p&gt;  &lt;h4&gt;&lt;a href="http://lh5.ggpht.com/_-FppOh0pKM8/SU1BhQM-6cI/AAAAAAAAD04/e0BVWwjnKVs/s1600-h/image%5B6%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://lh3.ggpht.com/_-FppOh0pKM8/SU1Bir9vhUI/AAAAAAAAD08/WdLBc3auo4I/image_thumb%5B4%5D.png?imgmax=800" width="416" height="291" /&gt;&lt;/a&gt;&lt;/h4&gt;  &lt;h4&gt;The Context&lt;/h4&gt;  &lt;p&gt;I have a number of ASP.NET server pages (aspx) that have one or more TextBox controls on them. Some of those text boxes need to have a popup calendar to allow a user to easily enter a valid date. I am using ASP.NET Validation server controls to inject so JavaScript to perform some simple user input checks like so:&lt;/p&gt;&lt;script src="http://gist.github.com/201762.js"&gt;&lt;/script&gt;&lt;p&gt;The popup calendar uses &lt;a target="_blank" href="http://docs.jquery.com/UI/Datepicker"&gt;jQuery’s UI&lt;/a&gt; project to provide a nice configurable widget without the overhead of a server control. Why use jQuery? Basically I wanted to simply add a CSS class to any TextBox to add a calendar rather than adding a bunch of server controls, one for each date field. So I have this at the top of the page to import the scripts:&lt;/p&gt;&lt;script src="http://gist.github.com/201757.js"&gt;&lt;/script&gt;&lt;p&gt;The gui.js is my own little script that basically hooks up any TextBox with a class of datePick with the jQuery datepicker widget like so:&lt;/p&gt;&lt;script src="http://gist.github.com/201754.js"&gt;&lt;/script&gt;&lt;h4&gt;The Problem&lt;/h4&gt;  &lt;p&gt;This all works great in Firefox and Chrome, but bombs in IE7 and IE8 every time. Well, it doesn’t bomb unless I choose to debug, but there is definitely a JavaScript error. What I see is the calendar popping up as expected. I can choose a date, but then the calendar stays displayed instead of gracefully closing to leave my new date in the text field. Why?&lt;/p&gt;  &lt;p&gt;After doing some Googling I found a great discussion on the jQuery discussion group about ASP.NET validation controls and how they interact with non-ASP.NET JavaScript. Basically the validation script is trying to fire every time the calendar widget calls it’s onSelect function, and because the calendar hasn’t yet put a value in the control the ASP.NET JavaScript errors out (thinks the length of the property array it’s checking is less than zero or just not there).&lt;/p&gt;  &lt;p&gt;This means that I can either have a nice jQuery calendar &lt;em&gt;or &lt;/em&gt;validation controls. Unless there’s a way around it all…&lt;/p&gt;  &lt;h4&gt;The Solution&lt;/h4&gt;  &lt;p&gt;Thanks entirely to the &lt;a target="_blank" href="http://groups.google.com/group/jquery-en/browse_frm/thread/a8902f2774edc05a/7205636697f1c54a?lnk=gst&amp;amp;q=asp.net+calendar+ui#7205636697f1c54a"&gt;supportive jQuery user mt&lt;/a&gt;&lt;font face="Courier New"&gt; &lt;/font&gt;I got a great workaround. Simply put, you need to subclass (or in jQuery terms, $.extend) the datepicker and override it’s onSelect method by setting it to nothing. Having done that, the calendar popup no longer interferes with what the ASP.NET-generated JavaScript is trying to do. Now I can have the best of both worlds. Here’s the fix in my gui.js:&lt;/p&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/201756.js"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3131102996085923653-4460321188265332206?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/4460321188265332206/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2008/12/jquery-and-aspnet-validation-controls.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/4460321188265332206'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/4460321188265332206'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2008/12/jquery-and-aspnet-validation-controls.html' title='jQuery and ASP.NET Validation Controls Disagree'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_-FppOh0pKM8/SU1Bir9vhUI/AAAAAAAAD08/WdLBc3auo4I/s72-c/image_thumb%5B4%5D.png?imgmax=800' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-3270822714284399153</id><published>2008-11-16T14:24:00.001-08:00</published><updated>2008-11-16T14:24:13.283-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wcf'/><title type='text'>WCF Experimentation</title><content type='html'>&lt;p&gt;I’ve been working on a Windows Communication Foundation (WCF) service at work this past week or so, and it’s taught me a few things about structuring projects correctly, and supporting unit tests.&lt;/p&gt;  &lt;p&gt;First, you can get the code here using your favorite Subversion client: &lt;a target="_blank" href="http://code.google.com/p/dylansknowledgebase/source/browse/#svn/trunk/WcfReferenceProject"&gt;http://code.google.com/p/dylansknowledgebase/source/browse/#svn/trunk/WcfReferenceProject&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Key points:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Do not try to create a WCF service using the New Project wizard in Visual Studio and expect to have something flexible or testable! That’s probably the biggest lesson of the week. I learned this through my struggles with the out-of-the-box arrangement that Microsoft provides, and got all of the &lt;em&gt;right &lt;/em&gt;answers from an excellent Dot Net Rocks TV episode by &lt;a target="_blank" href="http://www.dnrtv.com/default.aspx?showNum=122"&gt;Miguel Castro&lt;/a&gt;.&lt;/li&gt;    &lt;li&gt;Do not use any automated tools or cut’n’paste too much when working with the app.config or web.config for your services. I have a much better understanding of what the heck is going on by slowly and methodically adding my own settings and seeing what works and what doesn’t. It’s pretty painful at first but it pays off when you can quickly diagnose a problem that seems to be coming from nowhere, only to discover a simple fix in the system.serviceModel section of the file.&lt;/li&gt;    &lt;li&gt;Don’t use a Add Service Reference option in Visual Studio to automatically create your client proxy to the WCF service. Instead use ClientBase&amp;lt;T&amp;gt; to create a strongly type proxy very easily in code. It’s less work, and let’s you know &lt;em&gt;immediately&lt;/em&gt; if it no longer matches the server implementation. Plus, you can override the logic in your own client if you need to, e.g., adding user verification before uploading a large file. Look in ClientTests\HelloClient.cs for an example of this in action.&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;That’s it: pretty simple stuff, but it had a profound and positive impact on the way that I’m pursuing WCF.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3131102996085923653-3270822714284399153?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/3270822714284399153/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2008/11/wcf-experimentation.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/3270822714284399153'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/3270822714284399153'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2008/11/wcf-experimentation.html' title='WCF Experimentation'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-3211863418157647485</id><published>2008-11-12T16:44:00.001-08:00</published><updated>2009-05-06T18:58:16.589-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='automation'/><title type='text'>Automated Builds</title><content type='html'>&lt;p&gt;For the past few months I’ve been ramping up on my software building skills. Having cut my teeth on the .NET Framework, my weapon of choice for writing code has long been Visual Studio. Consequently I’ve always considered pushing F5 to be the extent of building software. Of course now I’m a little wiser and know the difference between compiling it and building something useful. In fact, the biggest impetus for me to learn how to run a more elaborate build process was working in a distributed team and needing to keep in sync. Anyway, what do I mean by building anyway?&lt;/p&gt;  &lt;h2&gt;Reducing Friction&lt;/h2&gt;  &lt;p&gt;A build process is simply a repeatable way to take a bunch of inputs and finish with a desired set of outputs. Think of a typical web application. It probably has some pages, some resources like images, CSS, JavaScript files, etc. But it also usually has one or more configuration files, 3rd party components, a database or two, and possibly even some management tools. Now imagine having to join a team of developers who are already writing that web site, and being productive immediately. This is where the build process comes in. It &lt;em&gt;should &lt;/em&gt;go something like this:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Open IDE&lt;/li&gt;    &lt;li&gt;Connect to version control system and download the trunk (most recent buildable version of the project)&lt;/li&gt;    &lt;li&gt;Read the Readme.txt file describing the build process.&lt;/li&gt;    &lt;li&gt;Run the build script&lt;/li&gt;    &lt;li&gt;Start working&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Unfortunately my prior experience has been more along these lines:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Open IDE&lt;/li&gt;    &lt;li&gt;Download the latest code&lt;/li&gt;    &lt;li&gt;Press F5 and wonder what all the errors are&lt;/li&gt;    &lt;li&gt;Ask the lead developer what I’m missing, and discover that there are three database I forgot to install, and a dependency for ASP.NET AJAX to XCOPY deploy first.&lt;/li&gt;    &lt;li&gt;Do what is suggested, still get a bunch of errors. Discover that there are 5 configuration settings that work on Bob’s PC but not on mine so I have to change them.&lt;/li&gt;    &lt;li&gt;Waste the rest of the day on this crap.&lt;/li&gt;    &lt;li&gt;Waste most of the next day on similar issues.&lt;/li&gt;    &lt;li&gt;Sometime towards the end of day three (I kid you not) I can actually start to write code and add value to the project.&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Which do you think I prefer?&lt;/p&gt;  &lt;p&gt;So the build process implies a couple of things: a &lt;u&gt;build tool&lt;/u&gt; that actually does all of the little bits and pieces for me like compiling code, setting up databases, adding users to systems, etc., and also a &lt;u&gt;build script&lt;/u&gt; that the build tool uses to do it’s thing. There are numerous build tools out there and they generally seem to be either code based, e.g., Rake uses a Ruby script, bake uses a Boo script, or heavy on the angle brackets, e.g., Ant (Java), Nant (.NET), and MSBuild (.NET) all rely on XML documents to describe the build process. Personally I really like the readability of rake (Ruby) scripts, and theoretically there’s no reason why I could use Rake on my .NET projects. However, I decided to tow the party line and use MSBuild for my first attempts and build scripts simply because is is guaranteed to be installed on every .NET developers machine: one less thing to worry about.&lt;/p&gt;  &lt;h2&gt;It doesn’t just happen&lt;/h2&gt;  &lt;p&gt;As I was reading all of the various ALT.NET and agile remonstrations for &lt;em&gt;not &lt;/em&gt;having a build process, I wondered why on earth everyone didn’t just do this stuff in the first place. Then I tried to create a build script to do the things I need to do and had a very rude awakening. It turns out to be fairly tough to learn MSBuild in the first place. As with anything, the initial frustration level was high enough to make me curse Microsoft up and down, but once I got the hang of it I found it relatively painless (like maybe stubbing your toe badly as opposed to slicing a finger off). In other words, I still find it to be a bit of a chore to keep up with the build script as things evolve, but here’s the lesson:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;Make sure your build script is one of the very first things you do on a fresh project. It’s a lot less painful to make small incremental steps than it is to figure it all out at the end of a project.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;In fact, maintaining a running build has become so central to my last couple of projects for that very reason. Think about this: in order to set up my current project I need to…&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Install 4 databases from scratch&lt;/li&gt;    &lt;li&gt;Install one web application&lt;/li&gt;    &lt;li&gt;Install two web service projects – one is mine, the other is a vendor solution&lt;/li&gt;    &lt;li&gt;Create web proxies dynamically each time the code in the web services change&lt;/li&gt;    &lt;li&gt;Update at least 10 config files&lt;/li&gt;    &lt;li&gt;etc.&lt;/li&gt;    &lt;li&gt;etc.&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Things absolutely go wrong with the build, but the great thing is when I fix something, it always works in the future, and if it breaks again it’s because something has changed that I probably needed to know about in the first place. It’s kind of like test driven development but for your whole project, not just for one tiny piece of it.&lt;/p&gt;  &lt;h2&gt;Next time&lt;/h2&gt;  &lt;p&gt;In my next post I’ll describe what is happening in my latest build script and how it helps the team of 4 developers in 3 time zones and 4 cities to keep tightly in sync.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3131102996085923653-3211863418157647485?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/3211863418157647485/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2008/11/automated-builds.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/3211863418157647485'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/3211863418157647485'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2008/11/automated-builds.html' title='Automated Builds'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-5943628447437080934</id><published>2008-11-11T14:39:00.001-08:00</published><updated>2008-11-11T14:40:13.835-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='asp.net'/><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><title type='text'>Getters and Setters</title><content type='html'>&lt;p&gt;I just burned about 30 minutes trying to figure out why my data transfer object (DTO) didn’t work. I have a C# Web Service (asmx) that accepts a simple class. There are two properties I care about:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;A unique ID which is an integer&lt;/li&gt;    &lt;li&gt;An array of another simple class with a few simple properties&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;No matter how hard I tried I could &lt;em&gt;not &lt;/em&gt;get the array property to show up. I know I’ve done this a million times before, but my proxy class (created by the wsdl command line tool) just wouldn’t generate the damn thing.&lt;/p&gt;  &lt;p&gt;Simple answer: I forgot to add a setter to the property, so while I could get the array, the serializer that .NET uses to XML-serialize the array could not be called. Rather than notify me of this, the wsdl command simply ignored the type when generating the proxy classes.&lt;/p&gt;  &lt;p&gt;So there you have it. Make sure your DTOs have:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;A parameterless constructor&lt;/li&gt;    &lt;li&gt;Getters and setters on properties you need to use on the client&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/3131102996085923653-5943628447437080934?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/5943628447437080934/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2008/11/getters-and-setters.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/5943628447437080934'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/5943628447437080934'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2008/11/getters-and-setters.html' title='Getters and Setters'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-3847812830821762690</id><published>2008-10-23T20:41:00.001-07:00</published><updated>2009-10-04T19:15:06.172-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='arcobjects'/><title type='text'>Capturing Edit Events in ArcMap</title><content type='html'>&lt;h3&gt;Issue&lt;/h3&gt;  &lt;p&gt;You are trying to capture the Save Edits and Stop Editing toolbar actions in &lt;a href="http://www.esri.com/arcgis"&gt;ArcMap&lt;/a&gt; through code so that different actions can be performed for each event. Unfortunately the underlying events associated with the actions (saving and stopping editing) fire for both actions so figuring out if the use Saved or Stopped Editing is a chore.&lt;/p&gt;  &lt;h3&gt;Resolution&lt;/h3&gt;  &lt;p&gt;Set up your code to listen for the events:&lt;/p&gt;&lt;script src="http://gist.github.com/201763.js"&gt;&lt;/script&gt;&lt;p&gt;Then put in whatever code you need to run on the Save Edits action. In this case there is no special code apart from the magic part where a boolean field is being set to &lt;code&gt;true&lt;/code&gt;. This basically lets the application know that “I just did a save action”.&lt;/p&gt;&lt;script src="http://gist.github.com/201764.js"&gt;&lt;/script&gt;&lt;p&gt;With that field set to true, when the OnStopEditing event fires just afterwards, we can look at that field to see whether or not a Save just ran as well:&lt;/p&gt;&lt;script src="http://gist.github.com/201765.js"&gt;&lt;/script&gt;&lt;p&gt;Note that we are &lt;u&gt;always&lt;/u&gt; setting the &lt;code&gt;_isSavedAction&lt;/code&gt; field to &lt;code&gt;false&lt;/code&gt; after any special code has run, and our special code only runs if the field is already false in the first place.&lt;/p&gt;  &lt;h3&gt;The Trick&lt;/h3&gt;  &lt;p&gt;Turns out this approach works very well, but it does not capture edit events caused by background edits. By background edit I means something done in a cursor behind the scenes while an edit session is active, e.g., doing a little update cursor action in your own code while a regular ArcMap edit session is in progress. This is documented by ESRI but took me a while to figure out. Fortunately the answer is simple: force these kind of background, cursor driven events to fire like all the others:&lt;/p&gt;&lt;script src="http://gist.github.com/201766.js"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3131102996085923653-3847812830821762690?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/3847812830821762690/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2008/10/capturing-edit-events-in-arcmap.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/3847812830821762690'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/3847812830821762690'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2008/10/capturing-edit-events-in-arcmap.html' title='Capturing Edit Events in ArcMap'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3131102996085923653.post-7429915062111922724</id><published>2008-10-23T19:58:00.001-07:00</published><updated>2008-10-23T19:58:28.384-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='general'/><title type='text'>Welcome to techno-world</title><content type='html'>&lt;p&gt;In the past I’ve posted a few articles related to my job as a software developer or more accurately a “technologist”. They have ended up on my &lt;a href="http://DylanDoesSeattle.blogspot.com"&gt;other blog&lt;/a&gt;, much to the consternation of my family and non-geek friends (which is to say, most of them). So I’m finally biting the bullet and creating a corner of the web for my own meanderings in software developments trials, database tribulations, and generally anything sort of work related that baffles me.&lt;/p&gt;  &lt;p&gt;In essence, then, this will be a memory dumping ground for all of the things that I keep forgetting shortly after having learned them. Similar to my &lt;a href="http://delicious.com/dvhthomas/"&gt;collection of bookmarks&lt;/a&gt;, only with more context.&lt;/p&gt;  &lt;p&gt;So don’t expect anything earth shattering here folks: just the musings of a barely competent propeller head trying to stay gainfully employed while continually getting in to trouble.&lt;/p&gt;  &lt;p&gt;By way of closing, I suppose I should warn you that you are likely to read about these topics here:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;.NET development with a focus on C#&lt;/li&gt;    &lt;li&gt;Software configuration management, particularly version control and automated builds.&lt;/li&gt;    &lt;li&gt;SQL Server and Oracle bits appropriate to a developer (I’m categorically &lt;em&gt;not &lt;/em&gt;a DBA so I’m likely to get it all wrong)&lt;/li&gt;    &lt;li&gt;Spatial stuff. No, not outer space but GIS and mapping kind of spatial.&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/3131102996085923653-7429915062111922724?l=dylandoesdigits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dylandoesdigits.blogspot.com/feeds/7429915062111922724/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dylandoesdigits.blogspot.com/2008/10/welcome-to-techno-world.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/7429915062111922724'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3131102996085923653/posts/default/7429915062111922724'/><link rel='alternate' type='text/html' href='http://dylandoesdigits.blogspot.com/2008/10/welcome-to-techno-world.html' title='Welcome to techno-world'/><author><name>Dylan Thomas</name><uri>http://www.blogger.com/profile/17927789133899144558</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://static.flickr.com/28/99392335_cd834f86ec_t.jpg'/></author><thr:total>0</thr:total></entry></feed>
