<?xml version="1.0" encoding="utf-8" ?>
<?xml-stylesheet href="/log/templates/default/atom.css" type="text/css" ?>

<feed 
   xmlns="http://www.w3.org/2005/Atom"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:admin="http://webns.net/mvcb/"
   xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
   xmlns:wfw="http://wellformedweb.org/CommentAPI/">
    <link href="http://shog9.com/log/feeds/atom10.xml" rel="self" title="Shog's Worklog" type="application/atom+xml" />
    <link href="http://shog9.com/log/"                        rel="alternate"    title="Shog's Worklog" type="text/html" />
    <link href="http://shog9.com/log/rss.php?version=2.0"     rel="alternate"    title="Shog's Worklog" type="application/rss+xml" />
    <title type="html">Shog's Worklog</title>
    <subtitle type="html">Nothing lies still long</subtitle>
    <icon>/head.jpg</icon>
    <id>http://shog9.com/log/</id>
    <updated>2008-05-26T13:44:14Z</updated>
    <generator uri="http://www.s9y.org/" version="1.3">Serendipity 1.3 - http://www.s9y.org/</generator>
    <dc:language>en</dc:language>

    <entry>
        <link href="http://shog9.com/log/archives/23-Cat5-Macrame-Plant-Hanger.html" rel="alternate" title="Cat5 Macramé Plant Hanger" />
        <author>
            <name>Shog9</name>
                    </author>
    
        <published>2008-01-08T04:27:54Z</published>
        <updated>2008-05-26T13:44:14Z</updated>
        <wfw:comment>http://shog9.com/log/wfwcomment.php?cid=23</wfw:comment>
    
        <slash:comments>8</slash:comments>
        <wfw:commentRss>http://shog9.com/log/rss.php?version=atom1.0&amp;type=comments&amp;cid=23</wfw:commentRss>
    
    
        <id>http://shog9.com/log/archives/23-guid.html</id>
        <title type="html">Cat5 Macramé Plant Hanger</title>
        <content type="xhtml" xml:base="http://shog9.com/log/">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>I was cleaning up around the house last Sunday evening... A drain had clogged, and in the process of getting it <i>un</i>clogged, things had become messy. Since I was cleaning anyway, I took the time to straighten up a few other areas, including some potted plants and cabling. When finished, I had a left-over mint plant, and forty-some feet of damaged Ethernet cable. Since I had plenty of other things to do, and didn't particularly want to do them, I spent a relaxing half-hour knotting a plant hanger with the cable. <br /><br />Twenty years ago, this would have been called "recycling". But in these enlightened times, I feel fully justified in calling it a "green" plant hanger. Even though it's blue. <br /><br /></p>

<p><a href="http://www.shog9.com/gallery/main.php?g2_itemId=3217" style="float: left;"><img src="http://www.shog9.com/gallery/main.php?g2_view=core.DownloadItem&amp;g2_itemId=3219&amp;g2_serialNumber=2" alt="Cat 5 Macramé" /></a></p>

<p><a href="http://www.shog9.com/gallery/main.php?g2_itemId=3208"><img src="http://www.shog9.com/gallery/main.php?g2_view=core.DownloadItem&amp;g2_itemId=3210&amp;g2_serialNumber=2" alt="Cat 5 Macramé" /></a></p>
 
            </div>
        </content>
        
    </entry>
    <entry>
        <link href="http://shog9.com/log/archives/22-CruiseControl.NET-Configuration-Error.html" rel="alternate" title="CruiseControl.NET: Configuration Error" />
        <author>
            <name>Shog9</name>
                    </author>
    
        <published>2007-10-17T01:51:25Z</published>
        <updated>2007-10-17T02:43:30Z</updated>
        <wfw:comment>http://shog9.com/log/wfwcomment.php?cid=22</wfw:comment>
    
        <slash:comments>1</slash:comments>
        <wfw:commentRss>http://shog9.com/log/rss.php?version=atom1.0&amp;type=comments&amp;cid=22</wfw:commentRss>
    
            <category scheme="http://shog9.com/log/categories/1-Worklog" label="Worklog" term="Worklog" />
    
        <id>http://shog9.com/log/archives/22-guid.html</id>
        <title type="html">CruiseControl.NET: Configuration Error</title>
        <content type="xhtml" xml:base="http://shog9.com/log/">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Just upgraded to CC.NET 1.3. And it didn't work. It <i>spectacularly </i>didn't work. Ok, it just didn't work:<br /></p>

<blockquote style="margin: 1em;"><span><h2><i>Configuration Error</i> </h2></span><font face="Arial, Helvetica, Geneva, SunSans-Regular, sans-serif "><b>Description:  </b>An error occurred during the processing of a configuration file required to  service this request. Please review the specific error details below and modify  your configuration file appropriately. <br /><br /><b>Parser Error Message: </b>The  format of the file 'ThoughtWorks.CruiseControl.WebDashboard' is invalid.</font><br /></blockquote>

<p>Unfortunate, that. After a few fruitless web searches, I re-installed 1.2, and of course, that worked. Which gave me an idea...<br /><br />Loaded 1.3 again, checked InetInfo settings, and sure 'nuff - it was still set to the 1.1 framework (1.3 is the first .NET 2.0 version of CC.NET). Change it to 2.0, and all was right with the world. <br /></p>
 
            </div>
        </content>
        
    </entry>
    <entry>
        <link href="http://shog9.com/log/archives/21-I-could-cry.html" rel="alternate" title="I could cry" />
        <author>
            <name>Shog9</name>
                    </author>
    
        <published>2007-09-25T23:10:57Z</published>
        <updated>2007-09-25T23:11:40Z</updated>
        <wfw:comment>http://shog9.com/log/wfwcomment.php?cid=21</wfw:comment>
    
        <slash:comments>1</slash:comments>
        <wfw:commentRss>http://shog9.com/log/rss.php?version=atom1.0&amp;type=comments&amp;cid=21</wfw:commentRss>
    
            <category scheme="http://shog9.com/log/categories/1-Worklog" label="Worklog" term="Worklog" />
    
        <id>http://shog9.com/log/archives/21-guid.html</id>
        <title type="html">I could cry</title>
        <content type="xhtml" xml:base="http://shog9.com/log/">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>After almost three days, i finally narrowed down an intermittent problem with a certain library. Turns out, it's contained within a rules engine we borrowed from another group. <br /><br />A rules engine that isn't thread-safe.<br /><br />It's 2007. We're using .NET. There's precious little need to make random variables static (er, rather, "Shared" - this is VB.NET). And it's trivially easy to add a bit of locking to avoid the problem, if you really <i>must</i> share the current rule with every other instance. <br /><br />Worse yet, this isn't even the problem i was trying to track down. <br /><br />So now, i'm tired, depressed, and no where near done. I know in my head that this isn't the fault of VB, but my heart still lays blame.<br /></p>
 
            </div>
        </content>
        
    </entry>
    <entry>
        <link href="http://shog9.com/log/archives/20-New-CPhog-released.html" rel="alternate" title="New CPhog released" />
        <author>
            <name>Shog9</name>
                    </author>
    
        <published>2007-07-05T21:30:29Z</published>
        <updated>2007-07-05T21:33:53Z</updated>
        <wfw:comment>http://shog9.com/log/wfwcomment.php?cid=20</wfw:comment>
    
        <slash:comments>1</slash:comments>
        <wfw:commentRss>http://shog9.com/log/rss.php?version=atom1.0&amp;type=comments&amp;cid=20</wfw:commentRss>
    
            <category scheme="http://shog9.com/log/categories/1-Worklog" label="Worklog" term="Worklog" />
    
        <id>http://shog9.com/log/archives/20-guid.html</id>
        <title type="html">New CPhog released</title>
        <content type="xhtml" xml:base="http://shog9.com/log/">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p><img src="http://www.shog9.com/log/uploads/CPhog1.9.Png" style="float:right;margin:.5em;border:none;" alt=""  />
I've just uploaded the <a href="http://www.greasespot.net/">GreaseMonkey</a> "boot" script for <a href="http://www.shog9.com/greasemonkey/scripts/cphog.user.js">CPhog 1.9.1</a><br /><br/>This will probably be the last release before I bite the bullet and go in for some major restructuring. I've been using it for months now, and it's reasonable solid... but there are just too many remnants of the quick-and-dirty little script i threw together a couple of years ago.<br /><br />Notable changes with this release include the ability to load threads longer than 50 posts, "QuickBio" pop-up user profiles, and "ForumWatch" panels. <br /><br />Under the hood, changes include lots more reliance on <a href="http://jquery.com/">jQuery</a> for DOM and plugin/content loading, some solid structure to new features (plugin-style loading rather than the "one huge script" style I'd labored under for so long), and the use of <font class="messagecontent"><a href="http://developer.mozilla.org/en/docs/DOM:Storage">GlobalStorage</a> instead of GM_setValue/GM_getValue (prefs.js). Many thanks to <a href="http://weblogs.asp.net/dstone/">David Stone</a> for his work on all of this, not to mention cleaning up a lot of my old code.</font><br /><br />More details <a href="http://www.shog9.com/greasemonkey/CPhog.html">here</a>...<br /></p>
 
            </div>
        </content>
        
    </entry>
    <entry>
        <link href="http://shog9.com/log/archives/19-Fit-acceptance-testing-and-OpenWiki.html" rel="alternate" title="Fit acceptance testing and OpenWiki" />
        <author>
            <name>Shog9</name>
                    </author>
    
        <published>2007-06-25T00:16:27Z</published>
        <updated>2007-06-25T05:46:43Z</updated>
        <wfw:comment>http://shog9.com/log/wfwcomment.php?cid=19</wfw:comment>
    
        <slash:comments>0</slash:comments>
        <wfw:commentRss>http://shog9.com/log/rss.php?version=atom1.0&amp;type=comments&amp;cid=19</wfw:commentRss>
    
            <category scheme="http://shog9.com/log/categories/2-Tips" label="Tips" term="Tips" />
            <category scheme="http://shog9.com/log/categories/1-Worklog" label="Worklog" term="Worklog" />
    
        <id>http://shog9.com/log/archives/19-guid.html</id>
        <title type="html">Fit acceptance testing and OpenWiki</title>
        <content type="xhtml" xml:base="http://shog9.com/log/">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p><img src="http://www.shog9.com/log/uploads/FitOutput.png" style="float: right;" alt=""  /><a href="http://www.nunit.org/">NUnit</a> now includes the <a href="http://fit.c2.com/">Framework for Integrated Test</a> (Fit) engine. I'm not entirely sure why (there seems to be some support for using it to run NUnit tests) but my curiosity upon seeing the new DLL led me to read more about Fit. And it couldn't have been more timely - the project I was working on had something like 47 test cases taken directly from sales orders, complete with supplier-provided "known good" outputs - a perfect <em>ahem</em> fit for Fit testing. <br /><br />And what a beautiful thing it is. A few minutes work, and the Excel spreadsheet of test cases was a HTML document suitable for feeding into the .NET version of Fit - much preferable to the manual translation of each scenario into a NUnit test, or (<em>shudder</em>) manually entering each case into my interactive testing app. I'd been planning on creating a bulk-testing interface anyway, and this just seemed too good to be true - it was almost exactly what I'd been planning, and saved me the time and effort of writing and debugging a custom CSV parser + test harness. <br /><br />The only thing lacking was integration with our wiki, which was the other part of my idle plan... Sure, there's <a href="http://fitnesse.org/">FitNesse</a> - but that just solves one problem with yet another wiki to maintain. <br /><br />So I hacked together an ASP.NET runner for Fit, threw it on our build machine, and then built in a new processing instruction to let OpenWiki forward on a page to this service for processing. <br /><br />Satisfaction!<br /><br />In case anyone else has a use for it, here's the code required:<br /><br /><i>OpenWiki #FITTESTS processing instruction (modify mywiki.asp)</i><br /></p>

<pre>Function MyWikifyProcessingInstructions(pText)<br />       <br />   ' other custom processing instructions...<br />   <br />   ' Fit integration: detect Fit processing instruction, flag for later processing<br />   dim FitPI, FitPILen<br />   FitPI = "#FITTESTS"<br />   FitPILen = Len(FitPI)<br />   if m(pText, "\n" &amp; FitPI &amp; "\s+", False, False) Then<br />      dim lineStart, lineEnd<br />      lineStart = InStr(pText, FitPI)<br />      lineEnd = InStr(lineStart, pText, vbCR)<br />      If lineEnd &gt; lineStart+FitPILen Then<br />         gFitTestPath = Trim(Mid(pText, lineStart+FitPILen, lineEnd - lineStart - FitPILen))<br />      End If<br />      pText = s(pText, "\n" &amp; FitPI &amp; "[^\r\n]*\r*\n", "", False, False)<br />   End If<br /><br />   ' other custom processing instructions...<br />   <br />    MyWikifyProcessingInstructions = pText<br />End Function</pre>

<p><br /><br /><i>Additional modifications to mywiki.asp - these actually call the testing web service after the page has been mostly built. </i><br /></p>

<pre>Function MyLastMinuteChanges(pText)<br /><br />   ' other custom last-minute changes...<br /><br />   ' Fit integration<br />   If (gAction = "view" and Len(gFitTestPath) &gt; 0 ) Then<br />      dim TestResults<br />      TestResults = RunFitTests(pText, gFitTestPath)<br />      If ( err.number &lt;&gt; 0 ) then<br />         pText = "&lt;i&gt;Error running tests: " &amp; err.description &amp; "&lt;/i&gt;&lt;br /&gt;" &amp; pText<br />      Elseif ( Len(TestResults) = 0 ) then<br />         pText = "<i>Unknown error running tests</i>" &amp; pText<br />      Else<br />         pText = TestResults<br />      End If<br />   End If<br /><br />   MyLastMinuteChanges = pText<br />End Function<br /><br />Function RunFitTests(pText, gFitTestPath)<br />   dim url<br />   dim verb<br />   dim form<br /><br />   ' location of FIT service. Need not be local.<br />   url = "http://localhost:8088/FitService.ashx"<br />   verb = "POST"<br />   form = "ClassPath=" &amp; Server.URLEncode(gFitTestPath) _<br />      &amp; "&amp;TestData=" &amp; Server.URLEncode(pText)<br />      <br />   on error resume next  <br />   <br />   dim xmlhttp<br />   set xmlhttp = Server.CreateObject("Msxml2.ServerXMLHTTP.4.0")<br />   if ( xmlhttp is nothing or err.number &lt;&gt; 0 ) then<br />      err.clear<br />      set xmlhttp = Server.CreateObject("Msxml2.ServerXMLHTTP")<br />   end if<br />   <br />   dim xmlDoc<br />   if ( err.number = 0 ) then<br />      xmlhttp.open verb, url, false ' synchronous<br />   end if<br />   <br />   if ( err.number = 0 ) then<br />      xmlhttp.setRequestHeader "Content-Type", "application/x-www-form-urlencoded" <br />      xmlhttp.send form<br />   end if<br />   <br />   ' try to figure out if it worked or not. And if not, why. VBS error handling... yuck.<br />   dim status<br />   if ( err.number = 0 ) then<br />      status = xmlhttp.status<br />   end if<br />   <br />   if (err.number &lt;&gt; 0) then<br />   elseif (status &lt;&gt; 200) then <br />      Err.Raise 65000, "", xmlhttp.statusText &amp; "(" &amp; status &amp; ")", "", 0<br />   else<br />      ' clean up Fit html<br />      RunFitTests = Replace(xmlhttp.ResponseText, "&amp;nbsp;", " ")<br />      RunFitTests = Replace(RunFitTests, "&lt;br&gt;", "&lt;br/&gt;")<br />      RunFitTests = Replace(RunFitTests, "&lt;hr&gt;", "&lt;hr/&gt;")<br />      RunFitTests = Replace(RunFitTests, "&lt;font size=-1", "&lt;font size='-1'")<br />   end if  <br />   <br />   set xmlhttp = nothing  <br />End Function<br /></pre>

<p><i>FitService.ashx - quick'n'dirty Fit runner. You might want to add some error handling...</i><br /></p>

<pre>&lt;%@ WebHandler Language="C#" Class="FitService" %&gt;<br /><br />using System;<br />using System.Web;<br />using fit;<br /><br />public class FitService : IHttpHandler<br />{<br /><br />   public void ProcessRequest(HttpContext context)<br />   {<br />      context.Response.ContentType = "text/html";<br />      context.Response.ContentEncoding = System.Text.Encoding.UTF8;<br /><br />      Fixture.assemblyDirs = context.Request.Form["ClassPath"].Split(new char[]{';'});<br />      <br />      Fixture fixture = new Fixture();<br />      Parse tables = new Parse(context.Request.Form["TestData"]);<br />      fixture.doTables(tables);<br />      tables.print(context.Response.Output);<br />   }<br /><br />   public bool IsReusable<br />   {<br />      get<br />      {<br />         return false;<br />      }<br />   }<br />}</pre>

<p><br /><br />With these in place, i can add a line to the beginning of any wiki entry:<br /></p>

<pre>#FITTESTS c:\MfgEngineInterface\Current build\</pre>

<p><br />...followed by a table containing the tests, and the tests will be automatically run and their results provided upon page generation.</p>
 
            </div>
        </content>
        
    </entry>
    <entry>
        <link href="http://shog9.com/log/archives/17-Page-1-of-13-results.html" rel="alternate" title="Page 1 of 13 results" />
        <author>
            <name>Shog9</name>
                    </author>
    
        <published>2007-06-17T20:14:32Z</published>
        <updated>2007-06-17T20:14:32Z</updated>
        <wfw:comment>http://shog9.com/log/wfwcomment.php?cid=17</wfw:comment>
    
        <slash:comments>0</slash:comments>
        <wfw:commentRss>http://shog9.com/log/rss.php?version=atom1.0&amp;type=comments&amp;cid=17</wfw:commentRss>
    
    
        <id>http://shog9.com/log/archives/17-guid.html</id>
        <title type="html">Page 1 of 13 results</title>
        <content type="xhtml" xml:base="http://shog9.com/log/">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Live Search is a funny sort of bird. <br /><br />Ok, <i>technically</i>, it's not a bird at all - it's a web site (or "web app", which is the trendy name for anything on The Internet that isn't a MySpace page...). But of course, I'm using "bird" here as slang for an unusual person.<br /><br />...Which doesn't really work either, since, as I already mentioned, Live Search is a web site (or web app) and not at all a person (which for the sake of this discussion I'll define as, "something you could converse with over lunch without having to carry both sides of the conversation <i>and</i> eat both lunches"). <br /><br />In case this has become confusing, allow me to try again: Live Search is a funny sort of web site. And not <i>just</i> because it seems to exist for the sole purpose of proving that Microsoft is every bit as hip as Google, like some sort of corporate 40-year-old in baggy shorts. Nor am I referring to the strange promotional tactics involving <i>paying </i>companies to use Live Search, though I could extend the metaphor to involve said 40yr-old buying beer for the kids.<br /><br />No, I find it funny today for a much more subtle reason:<br /><img src="http://www.shog9.com/log/uploads/livesearchresults1.png" alt=""  /><br />Now, how many pages of results are there... One, or thirteen?<br /><br />You can probably guess that the thirteen refers to the total number of results, but if you're guessing that they're all on Page 1, well, by the time you get to the end of the page you'll know you're wrong:<br /><img src="http://www.shog9.com/log/uploads/livesearchresults2.png" alt=""  /><br />Go figure, eh?<br /><br />Funny 'ol Web App...<br /></p>
 
            </div>
        </content>
        
    </entry>
    <entry>
        <link href="http://shog9.com/log/archives/15-Mourning-the-apparent-demise-of-WDevs.html" rel="alternate" title="Mourning the apparent demise of WDevs" />
        <author>
            <name>Shog9</name>
                    </author>
    
        <published>2007-06-17T18:59:09Z</published>
        <updated>2007-06-17T18:59:09Z</updated>
        <wfw:comment>http://shog9.com/log/wfwcomment.php?cid=15</wfw:comment>
    
        <slash:comments>0</slash:comments>
        <wfw:commentRss>http://shog9.com/log/rss.php?version=atom1.0&amp;type=comments&amp;cid=15</wfw:commentRss>
    
    
        <id>http://shog9.com/log/archives/15-guid.html</id>
        <title type="html">Mourning the apparent demise of WDevs</title>
        <content type="xhtml" xml:base="http://shog9.com/log/">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Given the site's MIA status, a few other WDevs alumni have started new blogs or are maintaining alternate sites:<br /><br /><a href="http://robmanderson.blogspot.com/">Rob's <i>Ultramaroon rises again</i></a><br /><a href="http://xacc.wordpress.com/">Leppie's <i>xacc.ide</i></a><br /><a href="http://blog.colinmackay.net/">Colin's <i>Stuff that's in my head</i></a><br /><a href="http://www.myxaml.com/blog2/">Marc Clifton's Blog</a><br /><a href="http://joshsmithonwpf.wordpress.com/">Josh Smith on WPF</a><br /><br />Sadly, plenty of others are just gone. <br /></p>
 
            </div>
        </content>
        
    </entry>
    <entry>
        <link href="http://shog9.com/log/archives/14-The-string-0000-00-00T000000-0500-is-not-a-valid-AllXsd-value..html" rel="alternate" title="The string '0000-00-00T00:00:00-05:00' is not a valid AllXsd value." />
        <author>
            <name>Shog9</name>
                    </author>
    
        <published>2007-06-17T07:47:08Z</published>
        <updated>2007-06-17T07:47:08Z</updated>
        <wfw:comment>http://shog9.com/log/wfwcomment.php?cid=14</wfw:comment>
    
        <slash:comments>0</slash:comments>
        <wfw:commentRss>http://shog9.com/log/rss.php?version=atom1.0&amp;type=comments&amp;cid=14</wfw:commentRss>
    
            <category scheme="http://shog9.com/log/categories/1-Worklog" label="Worklog" term="Worklog" />
    
        <id>http://shog9.com/log/archives/14-guid.html</id>
        <title type="html">The string '0000-00-00T00:00:00-05:00' is not a valid AllXsd value.</title>
        <content type="xhtml" xml:base="http://shog9.com/log/">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>This is one of several exceptions that started cropping up recently in a little web app I'd written to display bugs in our <a href="http://www.seapine.com/">TestTrack</a> database. <br />Turns out, the value represented a null date (the server is located in CDT, GMT-5); however, the .NET SOAP framework doesn't seem to handle such things. I don't know enough about SOAP to say which party is in the wrong, but it turns out the value was part of a source control record that I wasn't particularly interested in anyway, so I just ditched the field altogether - filename + revision # should be enough. <br /><br /></p>
 
            </div>
        </content>
        
    </entry>
    <entry>
        <link href="http://shog9.com/log/archives/13-Triple-bug!.html" rel="alternate" title="Triple bug!" />
        <author>
            <name>Shog9</name>
                    </author>
    
        <published>2007-06-11T22:00:34Z</published>
        <updated>2007-06-12T00:02:33Z</updated>
        <wfw:comment>http://shog9.com/log/wfwcomment.php?cid=13</wfw:comment>
    
        <slash:comments>0</slash:comments>
        <wfw:commentRss>http://shog9.com/log/rss.php?version=atom1.0&amp;type=comments&amp;cid=13</wfw:commentRss>
    
            <category scheme="http://shog9.com/log/categories/1-Worklog" label="Worklog" term="Worklog" />
    
        <id>http://shog9.com/log/archives/13-guid.html</id>
        <title type="html">Triple bug!</title>
        <content type="xhtml" xml:base="http://shog9.com/log/">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>The Interface called The Engine to verify The Data before passing The
Data to The Framework. This is redundant, as The Framework is already
responsible for verifying any data passed to it. Bug #1.<br /><br />The Framework called The Engine to verify The Data. Except, it skipped the call in all but two obscure scenarios. Bug #2. <br /><br />The Engine was broken, and would always fail anything passed to it for verification. Bug #3.<br /><br />None of this was unit tested, and so The Bugs lived in The Field for more than a year... Programmer Error!<br /></p>
 
            </div>
        </content>
        
    </entry>
    <entry>
        <link href="http://shog9.com/log/archives/11-Moved.html" rel="alternate" title="Moved" />
        <author>
            <name>Shog9</name>
                    </author>
    
        <published>2007-06-11T16:09:08Z</published>
        <updated>2007-06-11T16:09:08Z</updated>
        <wfw:comment>http://shog9.com/log/wfwcomment.php?cid=11</wfw:comment>
    
        <slash:comments>0</slash:comments>
        <wfw:commentRss>http://shog9.com/log/rss.php?version=atom1.0&amp;type=comments&amp;cid=11</wfw:commentRss>
    
    
        <id>http://shog9.com/log/archives/11-guid.html</id>
        <title type="html">Moved</title>
        <content type="xhtml" xml:base="http://shog9.com/log/">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p><a href="http://blogs.wdevs.com/shog9">WDevs</a> seems to be down, so I've moved some stuff here on the off-chance that it's of interest to anyone.</p>
 
            </div>
        </content>
        
    </entry>
    <entry>
        <link href="http://shog9.com/log/archives/6-WinInet-ASYNC-mode-sucks.html" rel="alternate" title="WinInet ASYNC mode sucks" />
        <author>
            <name>Shog9</name>
                    </author>
    
        <published>2007-03-30T20:59:00Z</published>
        <updated>2007-03-30T20:59:00Z</updated>
        <wfw:comment>http://shog9.com/log/wfwcomment.php?cid=6</wfw:comment>
    
        <slash:comments>0</slash:comments>
        <wfw:commentRss>http://shog9.com/log/rss.php?version=atom1.0&amp;type=comments&amp;cid=6</wfw:commentRss>
    
            <category scheme="http://shog9.com/log/categories/3-Rants" label="Rants" term="Rants" />
            <category scheme="http://shog9.com/log/categories/1-Worklog" label="Worklog" term="Worklog" />
    
        <id>http://shog9.com/log/archives/6-guid.html</id>
        <title type="html">WinInet ASYNC mode sucks</title>
        <content type="xhtml" xml:base="http://shog9.com/log/">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Spent most of the day wrestling with this wretched API. What a complete
waste of time. Tells me the request is complete, but wants me to wait
an unknown amount of time before actually letting me retrieve the
response. Ugh.<br /><br />Forget it. I'll just shove the whole thing off onto a separate thread and let that sit and wait for as long as it needs.</p>
 
            </div>
        </content>
        
    </entry>
    <entry>
        <link href="http://shog9.com/log/archives/3-Dump-calls.html" rel="alternate" title="Dump calls" />
        <author>
            <name>Shog9</name>
                    </author>
    
        <published>2007-03-22T18:56:00Z</published>
        <updated>2007-03-22T18:56:00Z</updated>
        <wfw:comment>http://shog9.com/log/wfwcomment.php?cid=3</wfw:comment>
    
        <slash:comments>0</slash:comments>
        <wfw:commentRss>http://shog9.com/log/rss.php?version=atom1.0&amp;type=comments&amp;cid=3</wfw:commentRss>
    
            <category scheme="http://shog9.com/log/categories/2-Tips" label="Tips" term="Tips" />
            <category scheme="http://shog9.com/log/categories/1-Worklog" label="Worklog" term="Worklog" />
    
        <id>http://shog9.com/log/archives/3-guid.html</id>
        <title type="html">Dump calls</title>
        <content type="xhtml" xml:base="http://shog9.com/log/">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>I'm working with a 3rd-party library that does some machine-specific
calculations. It's called through COM interop, and takes a <em>ton</em>
of parameters. When something doesn't come out right, it's nice to be
able to quickly view what's being send in and returned without spending
an excessive amount of time in the debugger... so I use this
quick-and-dirty little wrapper to dump them to the output window:<br /></p>

<pre>using System;<br />using System.Collections.Generic;<br />using System.Text;<br />using System.Reflection;<br />using System.Runtime.Remoting;<br />using System.Runtime.Remoting.Proxies;<br />using System.Runtime.Remoting.Messaging;<br />using System.Runtime.InteropServices;<br />using System.Diagnostics;<br /><br />public class DebugTraceProxy<br />   : RealProxy<br />{<br />   readonly MarshalByRefObject target;<br /><br />   public static T NewObject&lt;T&gt;()<br />   {<br />      return (T)(new DebugTraceProxy(typeof(T)).GetTransparentProxy());<br />   }<br /><br />   private DebugTraceProxy(Type t)<br />      : base(t)<br />   {<br />      target = (MarshalByRefObject)Activator.CreateInstance(t);<br />   }<br />   <br />   public override IMessage Invoke(IMessage msg)<br />   {<br />      IMethodCallMessage call = msg as IMethodCallMessage;<br /><br />      Debug.WriteLine(call.MethodName + &quot;:&quot;);<br />      for (int i = 0; i &lt; call.InArgCount; ++i)<br />      {<br />         string name = call.GetInArgName(i);<br />         object arg = call.GetInArg(i);<br />         Debug.WriteLine(&quot;   &quot; + name + &quot;: &quot; + DumpOb(arg));<br />      }<br /><br />      IMethodReturnMessage ret = RemotingServices.ExecuteMessage(target, (IMethodCallMessage)msg);<br /><br />      Debug.WriteLine(&quot;Returned:&quot;);<br />      for (int i = 0; i &lt; ret.OutArgCount; ++i)<br />      {<br />         string name = ret.GetOutArgName(i);<br />         object arg = ret.GetOutArg(i);<br />         Debug.WriteLine(&quot;   &quot; + name + &quot;: &quot; + DumpOb(arg));<br />      }<br />            <br />      return ret;<br />   }<br /><br />   private string DumpOb(object ob)<br />   {<br />      Type t = ob.GetType();<br />      if (t.IsPrimitive || t == typeof(string))<br />         return ob.ToString();<br /><br />      string obDesc = &quot;&quot;;<br />      FieldInfo[] infos = t.GetFields(BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance );<br />      if (infos.Length == 0)<br />         return ob.ToString();<br />      foreach (FieldInfo field in infos)<br />      {<br />         if (obDesc != &quot;&quot;)<br />            obDesc += &quot;, &quot;;<br />         obDesc += field.Name + &quot;: &quot; + field.GetValue(ob).ToString();<br />      }<br />      return obDesc;<br />   }<br />}</pre>

<p>To use it, I create the object like so:<br /></p>

<pre>CrazyOb myCrazyOb = DebugTraceProxy.NewObject&lt;crazyob&gt;();</pre>

<p><br />
Reflection... handy.</p>
 
            </div>
        </content>
        
    </entry>
    <entry>
        <link href="http://shog9.com/log/archives/2-VS2005-DataTips-for-MFC-collection-classes-CMap,-CArray,-etc..html" rel="alternate" title="VS2005 DataTips for MFC collection classes (CMap, CArray, etc.)" />
        <author>
            <name>Shog9</name>
                    </author>
    
        <published>2007-03-11T00:19:00Z</published>
        <updated>2007-06-09T23:07:40Z</updated>
        <wfw:comment>http://shog9.com/log/wfwcomment.php?cid=2</wfw:comment>
    
        <slash:comments>0</slash:comments>
        <wfw:commentRss>http://shog9.com/log/rss.php?version=atom1.0&amp;type=comments&amp;cid=2</wfw:commentRss>
    
            <category scheme="http://shog9.com/log/categories/2-Tips" label="Tips" term="Tips" />
            <category scheme="http://shog9.com/log/categories/1-Worklog" label="Worklog" term="Worklog" />
    
        <id>http://shog9.com/log/archives/2-guid.html</id>
        <title type="html">VS2005 DataTips for MFC collection classes (CMap, CArray, etc.)</title>
        <content type="xhtml" xml:base="http://shog9.com/log/">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p><a title="[fig. 3: the long, hard road through CMap]" href="http://www.flickr.com/photos/shog9/416944121/"><img width="502" height="359" border="2" align="right" alt="dbgtip_fig3" src="http://farm1.static.flickr.com/131/416944121_d3a9f1bb55_o.png" style="padding: 5px; margin-left: 5px;" /></a>I spend a lot of time debugging old code. Tracing through libraries written years ago, before the VC++ STL had reached maturity. And one of the often-frustrating aspects of this is how difficult it is to examine the contents of the old, MFC collection classes. <code>CDWordArray</code>, <code>CStringArray</code>, <code>CMapPtrToPtr</code>... not to mention the various templatized versions of these classes. While sometimes these can be easily replaced with newer, better-supported STL equivalents, often the effort involved outweighs the benefit.<br /></p>

<p><br />
At least for the array classes, it's only a minor inconvenience: the array pointer, and the size of the array are both readily available, and with these it's easy enough to view the contents.  <br />
<br />
But for the <code>CMap</code> classes, things get ugly. Internally, these objects are hash tables, with an array of buckets and each bucket a linked list. Viewing the contents of one of these maps in the debugger requires manually tracing the list of each bucket, then backing up and trying another bucket, then another... until you've found the item, or just given up.<br />
<br />
The <code>std::map&lt;&gt;</code> class, implemented as a red-black tree, should be just as much of an annoyance to view - however, it gets flattened into what <span style="font-style: italic;">looks</span> like an array:<br /></p>

<p><br />
<a title="[fig 4: std::map goodness]" href="http://www.flickr.com/photos/shog9/416944134/"><img width="579" height="240" alt="dbgtip_fig4" src="http://farm1.static.flickr.com/174/416944134_f4d123e9bc_o.png" /></a><br />
<br />
Handy, eh? So enough of tracing through buckets. <br />
Open <code>\Program Files\Microsoft Visual Studio 8\Common7\Packages\Debugger\autoexp.dat</code>, and at the end of the <code>[Visualizer]</code> section, add:<br /></p>

<pre>;------------------------------------------------------------------------------<br />;  CArray<br />;------------------------------------------------------------------------------<br />CArray&lt;*&gt;|CDWordArray|CWordArray|CByteArray|CUIntArray|CPtrArray|CObArray|CStringArray{<br />   preview<br />   (<br />      #( &quot;[&quot;, [$c.m_nSize], &quot;](&quot;,<br />         #array <br />         (<br />             expr : $c.m_pData[$i],<br />             size : $c.m_nSize<br />         ),<br />      &quot;)&quot;)<br />   )<br />   <br />   children<br />   (<br />      #(<br />         #array <br />         (<br />             expr : $c.m_pData[$i],<br />             size : $c.m_nSize<br />         )<br />      )   <br />   )<br />}</pre>

<p><br />
Start a debug session. You should now be able to quickly examine the various <code>CArray </code>(<code>CDWordArray</code>...) objects as easily as <code>std::vector&lt;...&gt;</code>s. Note that the <code>preview (...)</code> section controls what's viewed in the initial DataTip or watch line, while the <code>children(...)</code> section controls what's displayed when you expand it.<br />
<br /></p>

<p><a title="[fig 5: visible CArray data]" href="http://www.flickr.com/photos/shog9/416944139/"><img width="405" height="242" alt="dbgtip_fig5" src="http://farm1.static.flickr.com/188/416944139_675869ded2_o.png" /></a><br />
<br />
Now for the fun one. Start with:<br /></p>

<pre>;------------------------------------------------------------------------------<br />;  CMap<br />;------------------------------------------------------------------------------<br />CMap&lt;*&gt;|CMapPtrToPtr|CMapPtrToWord|CMapWordToPtr|CMapWordToOb|CMapStringToPtr|CMapStringToOb|CMapStringToString{<br />   preview<br />   (<br />      #( &quot;[&quot;, [$c.m_nCount], &quot;](&quot;,<br />         #array <br />         (<br />             expr : $c.m_pHashTable[$i],<br />             size : $c.m_nHashTableSize<br />         ) : #list (<br />                 head : &amp;$e,<br />                 next : pNext<br />             ) : $e,<br />      &quot;)&quot;)<br />   )<br />   <br />   children<br />   (<br />      #(<br />         #array <br />         (<br />             expr : $e.m_pHashTable[$i],<br />             size : $e.m_nHashTableSize<br />         ) : #list (<br />                 head : &amp;$e,<br />                 next : pNext<br />             ) : $e<br />      )         <br />   )<br />}</pre>

<p><br />
Ah, now this one will save some serious time - it'll flatten the various <code>CMap</code> objects such that they look like arrays in the debugger. A <code>CMap</code> with 3000 items will show 3000 children, numbered 0-2999. <br />
<br />
<a title="[fig 6: visible CMap pairs]" href="http://www.flickr.com/photos/shog9/416944157/"><img width="370" height="240" alt="dbgtip_fig6" src="http://farm1.static.flickr.com/161/416944157_001c545ad3_o.png" /></a><br />
<br />
But it can still be better: each of those children is a key-value pair, specifically a <code>CMap::CAssoc</code> object. It'd be nice if we could get a preview of those keys and values as we scroll through those 3000 items, rather than having to expand each one...<br /></p>

<pre>CMap&lt;*&gt;::CAssoc|CMapPtrToPtr::CAssoc|CMapPtrToWord::CAssoc|CMapWordToPtr::CAssoc|CMapWordToOb::CAssoc|CMapStringToPtr::CAssoc|CMapStringToOb::CAssoc|CMapStringToString::CAssoc {<br />   preview<br />   (<br />      #( <br />         &quot;(&quot;, <br />         $e.key, <br />         &quot;,&quot;, <br />         $e.value, <br />         &quot;)&quot;<br />      )<br />   )<br />   <br />   children<br />   (<br />     #(<br />         key: $c.key,<br />         value: $c.value<br />     )<br />   )<br />}</pre>

<p><br />
<a title="[fig 7: visible CMap data]" href="http://www.flickr.com/photos/shog9/416944168/"><img width="369" height="240" border="2" align="right" alt="dbgtip_fig7" src="http://farm1.static.flickr.com/134/416944168_ca4854cd26_o.png" style="padding: 5px; margin-left: 5px;" /></a> There! All happy.  <br clear="all" />
<br />
Of course, you can write rules for your own datatypes too, if you want them to be immediately visible in the preview. For a good reference, see the excellent writeup over at <a href="http://www.virtualdub.org/blog/pivot/entry.php?id=120" style="font-weight: bold;">virtualdub.org</a></p>
 
            </div>
        </content>
        
    </entry>
    <entry>
        <link href="http://shog9.com/log/archives/5-Why-I-hate-software.html" rel="alternate" title="Why I hate software" />
        <author>
            <name>Shog9</name>
                    </author>
    
        <published>2007-03-02T16:09:00Z</published>
        <updated>2007-03-02T16:09:00Z</updated>
        <wfw:comment>http://shog9.com/log/wfwcomment.php?cid=5</wfw:comment>
    
        <slash:comments>0</slash:comments>
        <wfw:commentRss>http://shog9.com/log/rss.php?version=atom1.0&amp;type=comments&amp;cid=5</wfw:commentRss>
    
            <category scheme="http://shog9.com/log/categories/3-Rants" label="Rants" term="Rants" />
    
        <id>http://shog9.com/log/archives/5-guid.html</id>
        <title type="html">Why I hate software</title>
        <content type="xhtml" xml:base="http://shog9.com/log/">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>&quot;I'll
buy it if I want it and can't write it&quot;. Or, to put it another way, if
I think I could cook up the app myself in a Saturday's worth of hacking
and drinking, then I expect to get it free. That might not be entirely reasonable... but it's how i think. The result of this is that for smaller programs, I tend to open my wallet for the ones that <i>really </i>go above and beyond the norm.</p>

<p>Notable &quot;utility&quot; apps I've
laid out money for in the past few years:</p>

<ul><li>Trillian</li><li>TV Tool (a nice little utility for bypassing the onerous DRM restrictions and sad TV support implemented by NVidia drivers).</li><li>Nero</li><li>Firebug (ok, this was a donation… but I’d have paid it if I’d needed to)</li></ul>

<p>They all do things I needed, couldn't get free, and would have spent
months working out on my own. And with the exception of Firebug, they
all have terrible user interfaces. Heck, just about every single app I
use has a rotten UI. VS2005 is probably one of the better apps, but it
can hardly be classified as &quot;utility&quot; - it's huge, written by hundreds
of developers, and… still has a lot of problems. I certainly would
never use words like &quot;beautifully&quot; (or even &quot;seamlessly&quot;) to describe
how they integrate with the core system. Indeed, if there's one thing
common to most of the apps I use, it’s how eager they are to <em>make you aware that you’re using them</em>.
Splash screens, heavy UIs, custom dialogs for things that the system
does better, modal dialogs for things that should be non-modal… </p>

<p>…but such ranting gets old, eventually. Instead, I'll just give an example: source control.</p>

<p><em>At this moment</em>, I have four source control clients
installed on this machine. Three of them offer &quot;integration&quot; by way of
a Visual Studio plug-in. But only the fourth actually integrates at all
well into my workflow: the TortoiseSVN client makes source control <em>almost</em>
seamlessly available from any OS-provided file system view, including
the standard Open and Save dialogs. The rest all provide pale
imitations of the old two-pane Fileman/Explorer interface, usually with
a few more panes tacked on for for status or other information. All
three, <em>without </em>fail, require me to have either a command
prompt or an Explorer window open on the &quot;working directory&quot; for
whatever project I’m viewing, because they don’t provide a UI for
common file management tasks. And that token nod at “integration”? VS
becomes slower with it turned on, and continually locks files I don’t
want locked. In short, they provide the worst of both worlds: UIs I
could have written on a drunken Saturday, but <em>would never have wanted to</em>.
Tortoise, for all its problems, provides something I’d willingly pay
for out of pocket: I’m actually more productive with it than without
it. None of the rest, paid commercial products though they are, comes
close to this.<br />
</p>

<p><a href="http://paulmwatson.com/journal/2007/03/01/wallet-loosening-macs/">So, Paul - I'm glad you're happy with Mac software</a>. I don't know that I really believe it's as good as what you make it out to be, but I'll believe it is that good <span style="font-style: italic;">for you</span>. Because, somewhere, someone <em>must</em> be writing usable software. I <em>want </em>to believe it...</p>
 
            </div>
        </content>
        
    </entry>
    <entry>
        <link href="http://shog9.com/log/archives/4-Tables-and-numbers-and-colorful-graphs-and....html" rel="alternate" title="Tables and numbers and colorful graphs and..." />
        <author>
            <name>Shog9</name>
                    </author>
    
        <published>2007-02-26T15:44:00Z</published>
        <updated>2007-02-26T15:44:00Z</updated>
        <wfw:comment>http://shog9.com/log/wfwcomment.php?cid=4</wfw:comment>
    
        <slash:comments>0</slash:comments>
        <wfw:commentRss>http://shog9.com/log/rss.php?version=atom1.0&amp;type=comments&amp;cid=4</wfw:commentRss>
    
            <category scheme="http://shog9.com/log/categories/1-Worklog" label="Worklog" term="Worklog" />
    
        <id>http://shog9.com/log/archives/4-guid.html</id>
        <title type="html">Tables and numbers and colorful graphs and...</title>
        <content type="xhtml" xml:base="http://shog9.com/log/">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>A while back, I needed to generate some reports off of a small database
I maintain. I needed them to be updated frequently, and didn't want to
spend a lot of time putting them together. <br />
<br />
Of course, I could have used Crystal Reports. But it just didn't seem
right - I keep a large number of knives at home, and should I ever
desire death by a thousand cuts, I'm sure it could be arranged on my
own time. No reason to mix such activities with work.<br />
<br />
So based on a recommendation, I decided to give SQL Server Reporting
Services a shot. Installed it on my desktop, threw together a few
reports, and that was it. It was quick and easy, and I was happy. Until
it suddenly stopped working. I messed around with keys and permissions
and database users, and after about a day it was all working again...
until, roughly a month later, it suddenly wasn't. This went on for some
time, and then, one day, it was time to bring the reports out of
development and make them available to other people. <br />
<br />
And I balked. Here it was, running on a local machine that had no other
users, no onerous loads, a machine that, most days, ran only one very
light application... and it was still breaking periodically. Did I <em>really </em>want to put up with babysitting this thing on a remote server? No, I decided, I did not want that.<br />
<br />
So, back to the drawing board. Of course, I didn't exactly have time to
research and learn a whole new reporting framework. Heck, I didn't have
time to do much of anything - any work would have to be done while
waiting for builds to complete or tests to run on other projects. So I
buckled down and started coding: I needed a few basic statistical
routines, a histogram routine, some tables, and a few graphs. Some
quick-and-dirty C# took care of the stats, quick-and-dirty HTML for the
tables... and the <a href="http://zedgraph.org/">newest addition</a> to my toolbox took care of the graphs.<br />
<br />
I'd first run across ZedGraph a few years ago, when John Champion posted <a href="http://www.codeproject.com/csharp/zedgraph.asp">his article</a>
on The CodeProject. While it looked nice enough, I had no need for such
a thing at the time, and forgot about it. But now, running across it in
a frantic <a href="http://www.google.com/coop/cse?cx=008728878598828748424%3A32wunwqmfl8">Google search</a>,
it looked like just what I needed. A couple of hours spent playing with
it confirmed this notion: it fit my simple needs like a glove, quickly
turning the dry, drab reports into slick, colorful affairs, ready for
inclusion in any presentation. Best yet, <a href="http://zedgraph.org/wiki/index.php?title=Use_RenderMode.RawImage_in_a_web_page">it fit neatly</a> into the quick-and-dirty ASP.NET code I'd already written. <br />
<br />
A full day spent hacking (during the aforementioned gaps in
testing...), and the new reports were ready. Fast, ridiculously simple,
and perfectly suitable for XCOPY deployment.</p>
 
            </div>
        </content>
        
    </entry>

</feed>