<?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-8772123162990273002</id><updated>2012-01-26T05:43:04.853-05:00</updated><category term='sf'/><category term='beer'/><category term='computers'/><category term='programming'/><title type='text'>Invalid Object</title><subtitle type='html'>computers, programming, science fiction, beer</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>57</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-7813068611516497620</id><published>2010-09-19T23:02:00.002-04:00</published><updated>2010-09-19T23:02:55.755-04:00</updated><title type='text'>Programming Jargon</title><content type='html'>I found &lt;a href="http://stackoverflow.com/questions/2349378/new-programming-jargon-you-coined/2349399"&gt;this&lt;/a&gt; amusing.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-7813068611516497620?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/7813068611516497620/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2010/09/programming-jargon.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/7813068611516497620'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/7813068611516497620'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2010/09/programming-jargon.html' title='Programming Jargon'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-1233347662195777307</id><published>2010-02-24T11:10:00.004-05:00</published><updated>2010-02-25T07:35:03.075-05:00</updated><title type='text'>Pastebin test</title><content type='html'>Will pastebin enable be to post code snippets in my blog?&lt;br /&gt;
&lt;script src="http://pastebin.com/embed_js.php?i=tQ93gHcX"&gt;&lt;/script&gt;&lt;br /&gt;
Wow.  I really like this.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-1233347662195777307?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/1233347662195777307/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2010/02/pastebin-test.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/1233347662195777307'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/1233347662195777307'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2010/02/pastebin-test.html' title='Pastebin test'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-6998430636913065109</id><published>2010-01-07T11:47:00.003-05:00</published><updated>2010-01-07T12:36:28.392-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>TFS Build Adventure</title><content type='html'>We moved to TFS in 2009.&amp;nbsp; Source control itself was a great improvement from VSS.&amp;nbsp; But it became my job to manage the continuous integration process.&lt;br /&gt;
&lt;br /&gt;
I remember a java project I was on where our architect set up cruise control to deliver the latest version of the nightly build to the web server every night.&amp;nbsp; I want to set up something like that myself.&lt;br /&gt;
&lt;br /&gt;
Setting up the build wasn't too tough.&amp;nbsp; It makes a directory that contains all the products from the build in one big list.&amp;nbsp; The websites themselves are in subdirectories called "_Published Websites".&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;First goal&lt;/b&gt;: how to get the build service to copy the files to the inetpub directory.&lt;br /&gt;
&lt;br /&gt;
First of all, this thing is a monster.&amp;nbsp; MSBuild and TFSBuild, which read the .proj files to perform builds, have their own four-hundred page instruction manual.&amp;nbsp; Just trying to read this thing to get a hint of what to do is overwhelming.&amp;nbsp; So I decided to start with something simple.&amp;nbsp; Just copying some files after the build is done.&lt;br /&gt;
&lt;br /&gt;
There seems to be more than &lt;a href="http://www.tfsbuild.com/XcopyDeployWebApplication.ashx"&gt;one&lt;/a&gt;&lt;a href="http://www.tfsbuild.com/DeployingWebApplicationToIIS.ashx"&gt; way&lt;/a&gt; of doing the same thing.&amp;nbsp; I tried to do the simplest thing possible.&amp;nbsp; I just wanted the build to copy the website to publish to the inetpub directory of the development web server.&amp;nbsp; So I borrowed from the code listed &lt;a href="http://www.tfsbuild.com/XcopyDeployWebApplication.ashx"&gt;here &lt;/a&gt;and added this to the end of the TFSBuild.proj file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/ItemGroup&amp;gt;&lt;br /&gt;
&amp;nbsp; &amp;lt;Target Name="BeforeTest"&amp;gt;&lt;br /&gt;
&amp;nbsp; &amp;lt;CreateProperty value="w:\inetpub\gavintest"&amp;gt;&lt;br /&gt;
&amp;nbsp; &amp;lt;Output TaskParameter="Value" PropertyName ="MyDropLocation" /&amp;gt;&lt;br /&gt;
&amp;nbsp; &amp;lt;/CreateProperty&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp; &amp;lt;Exec Command='xcopy /y /e "$(OutDir)_PublishedWebsites\AgileGaWeb" $(MyDropLocation)' /&amp;gt;&lt;br /&gt;
&amp;lt;/Target&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here's what this code did:&amp;nbsp; It overrides the BeforeTest target.&amp;nbsp; Each target is run in succession by the default build process.&amp;nbsp; This code just replaces the "BeforeTest" target to inject its own action.&lt;br /&gt;
&lt;br /&gt;
The first thing we do is create a property we can pass to the Exec command below.&amp;nbsp; The property is "MyDropLocation", which is the path to the virtual directory.&amp;nbsp; &lt;br /&gt;
&lt;br /&gt;
Then we execute the xcopy command and pass it the source as a constant and the destination as the property.&amp;nbsp; I already set up the directory.&lt;br /&gt;
&lt;br /&gt;
Queue up the build and voila!&amp;nbsp; The new app is deployed with the automatic build.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Future Topics:&lt;/b&gt;&lt;br /&gt;
Running unit tests&lt;br /&gt;
Variable substitution in config files&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-6998430636913065109?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/6998430636913065109/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2010/01/tfs-build-adventure.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/6998430636913065109'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/6998430636913065109'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2010/01/tfs-build-adventure.html' title='TFS Build Adventure'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-1074486262930015103</id><published>2009-11-12T12:31:00.000-05:00</published><updated>2009-11-12T12:31:28.769-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='computers'/><title type='text'>Asimov and the TRS-80</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_cuJk5OBwokQ/SvxFLEl7GRI/AAAAAAAAAX4/Lp5zk-E3WNU/s1600-h/04-radio-shack-asimov.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_cuJk5OBwokQ/SvxFLEl7GRI/AAAAAAAAAX4/Lp5zk-E3WNU/s400/04-radio-shack-asimov.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;Cool things about this picture in order of priority:&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;Pocket TRS-80&lt;/li&gt;
&lt;li&gt;Sideburns&lt;/li&gt;
&lt;li&gt;Bolo tie&lt;/li&gt;
&lt;li&gt;Birth-control classes&lt;/li&gt;
&lt;li&gt;Asimov&lt;br /&gt;
&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/8772123162990273002-1074486262930015103?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/1074486262930015103/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2009/11/asimov-and-trs-80.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/1074486262930015103'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/1074486262930015103'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2009/11/asimov-and-trs-80.html' title='Asimov and the TRS-80'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_cuJk5OBwokQ/SvxFLEl7GRI/AAAAAAAAAX4/Lp5zk-E3WNU/s72-c/04-radio-shack-asimov.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-922848992413138032</id><published>2009-11-09T11:56:00.004-05:00</published><updated>2009-11-10T14:46:45.620-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Windows Command-line Fu</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_cuJk5OBwokQ/SvhJtZeEajI/AAAAAAAAAXo/QOUbetUCtYQ/s1600-h/flynn.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_cuJk5OBwokQ/SvhJtZeEajI/AAAAAAAAAXo/QOUbetUCtYQ/s200/flynn.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
This command executes the contents of your SQL script from a command line: &lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: small;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;sqlcmd -S ServerName\InstanceName -d DatabaseName -i test.sql&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
This command iterates through every file in a given directory: (and just echoes it to standard out)&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: small;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;for /R %f IN (dir *.sql) DO echo %f&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Put them together and you can execute all the scripts in a given directory:&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: small;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;for /R %f in (dir *.sql) DO &lt;/span&gt;&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;span style="font-size: small;"&gt;sqlcmd -S ServerName\InstanceName -d DatabaseName -i %f&lt;/span&gt;&lt;br /&gt;
&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-922848992413138032?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/922848992413138032/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2009/11/windows-command-line-fu.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/922848992413138032'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/922848992413138032'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2009/11/windows-command-line-fu.html' title='Windows Command-line Fu'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_cuJk5OBwokQ/SvhJtZeEajI/AAAAAAAAAXo/QOUbetUCtYQ/s72-c/flynn.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-5240520665349502821</id><published>2009-11-05T20:58:00.002-05:00</published><updated>2009-11-05T21:01:22.888-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='computers'/><title type='text'>Smartphone time?</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_cuJk5OBwokQ/SvOA752DKoI/AAAAAAAAAXg/DWLuEMQuUG0/s1600-h/101_0886.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_cuJk5OBwokQ/SvOA752DKoI/AAAAAAAAAXg/DWLuEMQuUG0/s320/101_0886.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;My Verizon service is good because it works well everywhere I go, but there are no decent smartphones available for the service because it doesn't use the more modern cell tower technology. &amp;nbsp;&lt;a href="http://gizmodo.com/5397461/htc-droid-eris-last-months-killer-android-now-99-bucks-on-verizon"&gt;This week I found out Verizon is going to offer a smartphone running the Android operating system.&amp;nbsp;&amp;nbsp;&lt;/a&gt;This is exciting to me because I am addicted to the services Google offers, especially with communication and calendering. &lt;br /&gt;
&lt;br /&gt;
So how much would this cost me? &amp;nbsp;Turns out I could get the phone for a hundred bucks, which isn't too bad, but I have to commit to another two years of service. &amp;nbsp;That sucks a little. &amp;nbsp;And I'd have to pay the data fee. &amp;nbsp;I'd have to pay another $20 per month for two years, and that's $480 more bucks! &amp;nbsp;I'm thinking if I want a handheld gadget that syncs with Google, I ought to consider the &lt;a href="http://store.apple.com/us/browse/home/specialdeals/ipod/ipod_touch"&gt;iPod Touch instead&lt;/a&gt;. &amp;nbsp;I can still listen to music, sync with Google, read Kindle books, and I can just do the sync thing in my house with 802.11 rather than the expensive data plan.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-5240520665349502821?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/5240520665349502821/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2009/11/smartphone-time.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/5240520665349502821'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/5240520665349502821'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2009/11/smartphone-time.html' title='Smartphone time?'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_cuJk5OBwokQ/SvOA752DKoI/AAAAAAAAAXg/DWLuEMQuUG0/s72-c/101_0886.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-992990663686356442</id><published>2009-11-04T09:10:00.004-05:00</published><updated>2009-11-04T21:18:22.995-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='beer'/><title type='text'>Rogue Dead Guy Ale</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_cuJk5OBwokQ/SvGLEIZGkBI/AAAAAAAAAXY/tXgEvmAEywY/s1600-h/dead-guy-ale-label.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_cuJk5OBwokQ/SvGLEIZGkBI/AAAAAAAAAXY/tXgEvmAEywY/s320/dead-guy-ale-label.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;A few months ago, this was the beer of the week at &lt;a href="http://www.lovethebeer.com/"&gt;RFD&lt;/a&gt;.&amp;nbsp; I drank two or three of them and they were quite good.&amp;nbsp; I bought a six-pack last weekend for about $11.&amp;nbsp; That's more than I would normally spend on microbrews, but it was really good!&lt;br /&gt;
&lt;br /&gt;
I think it tastes better on tap.&amp;nbsp; Considering it was the week of Halloween, I guess I can say it was in the spirit of the holiday.&amp;nbsp; But Dogfish Head seems to be a better buy.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-992990663686356442?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/992990663686356442/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2009/11/rouge-dead-guy-ale.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/992990663686356442'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/992990663686356442'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2009/11/rouge-dead-guy-ale.html' title='Rogue Dead Guy Ale'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_cuJk5OBwokQ/SvGLEIZGkBI/AAAAAAAAAXY/tXgEvmAEywY/s72-c/dead-guy-ale-label.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-4006203382423981974</id><published>2009-11-04T09:01:00.001-05:00</published><updated>2009-11-04T15:42:27.429-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='computers'/><title type='text'>Best Slashdot comment ever</title><content type='html'>From &lt;a href="http://tech.slashdot.org/comments.pl?sid=1430036&amp;amp;cid=29972684"&gt;here&lt;/a&gt;:&lt;br /&gt;
&lt;br /&gt;
A great deal of Microsoft security is unfortunately just like the underwear of  Brittany Spears.&amp;nbsp; If it's even there at all it's needlessly complex and  frilly, looks good without actually covering much and is far too easy to get  around or remove completely.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-4006203382423981974?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/4006203382423981974/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2009/11/best-slashdot-comment-ever.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/4006203382423981974'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/4006203382423981974'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2009/11/best-slashdot-comment-ever.html' title='Best Slashdot comment ever'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-1851630585225094621</id><published>2009-09-22T13:10:00.003-04:00</published><updated>2009-11-04T15:42:46.370-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Delete a project in TFS 2008</title><content type='html'>If you want to completely remove a project from Team Foundation Server 2008, here's the command:  C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE&amp;gt;TFSDeleteProject.exe  Run it to see what the command switches are.  The server name should be expressed as http://server-name:port/&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-1851630585225094621?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/1851630585225094621/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2009/09/delete-project-in-tfs-2008.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/1851630585225094621'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/1851630585225094621'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2009/09/delete-project-in-tfs-2008.html' title='Delete a project in TFS 2008'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-1902400379699922550</id><published>2009-08-11T05:54:00.005-04:00</published><updated>2009-08-11T08:13:22.148-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sf'/><title type='text'>Star Trek on YouTube</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_cuJk5OBwokQ/SoFB-c6oWOI/AAAAAAAAAQg/BWf2JWPjJZg/s1600-h/ST_intro_KirkSpock.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 300px; height: 280px;" src="http://1.bp.blogspot.com/_cuJk5OBwokQ/SoFB-c6oWOI/AAAAAAAAAQg/BWf2JWPjJZg/s320/ST_intro_KirkSpock.jpg" alt="" id="BLOGGER_PHOTO_ID_5368644771972143330" border="0" /&gt;&lt;/a&gt;If you had told me when I was a kid, someday, I would be watching &lt;a href="http://www.youtube.com/show/startrek"&gt;Star Trek&lt;/a&gt; on my PC, I wouldn't have believed you.&lt;div&gt;
&lt;/div&gt;&lt;div&gt;After I watch an episode, I like to read the &lt;a href="http://www.tor.com/index.php?option=com_content&amp;amp;view=blog&amp;amp;id=21428"&gt;analysis of it&lt;/a&gt; at the Tor books web site.&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;My only beef with Youtube is the sound quality.  When the show is running, the overall volume is a certain level.  Watching a single commercial for each break isn't so bad, but the volume is much greater.  So after Bones tells Kirk he's dead, I get to hear Brooke Shields shouting about toothpaste as I lunge across the room, spilling my beer and fumbling for the volume control.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-1902400379699922550?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/1902400379699922550/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2009/08/star-trek-on-youtube.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/1902400379699922550'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/1902400379699922550'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2009/08/star-trek-on-youtube.html' title='Star Trek on YouTube'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_cuJk5OBwokQ/SoFB-c6oWOI/AAAAAAAAAQg/BWf2JWPjJZg/s72-c/ST_intro_KirkSpock.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-2273260509999003876</id><published>2009-06-05T10:47:00.002-04:00</published><updated>2009-06-05T16:02:31.626-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Writing to the Windows Event Log</title><content type='html'>This is the bare minimum code you need to write something to the event log in Windows.  I find myself looking this up about once every few months.

&lt;pre&gt;
   class Program
   {
       static void Main(string[] args)
       {
           var message = args[0];
           var log = new EventLog();
           log.Source = "LogThis.exe";
           log.Log = "Application";
           log.WriteEntry(message, EventLogEntryType.Information);
       }
   }
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-2273260509999003876?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/2273260509999003876/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2009/06/writing-to-windows-event-log.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/2273260509999003876'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/2273260509999003876'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2009/06/writing-to-windows-event-log.html' title='Writing to the Windows Event Log'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-9003415094067400802</id><published>2009-04-21T15:33:00.004-04:00</published><updated>2009-04-21T15:40:48.619-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>C# ?? Operator</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_cuJk5OBwokQ/Se4hJt4UZ9I/AAAAAAAAAMg/l4NbqZC8H3w/s1600-h/question.jpeg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 122px; height: 108px;" src="http://3.bp.blogspot.com/_cuJk5OBwokQ/Se4hJt4UZ9I/AAAAAAAAAMg/l4NbqZC8H3w/s320/question.jpeg" alt="" id="BLOGGER_PHOTO_ID_5327231860044228562" border="0" /&gt;&lt;/a&gt;
&lt;div style="text-align: left;"&gt;
&lt;/div&gt;




Rather than write something awkward like this:
&lt;pre&gt;if (myList != null)
{
 return myList;
}
else
{
 return null;
}
&lt;/pre&gt;Try using the ?? operator instead:

&lt;pre&gt;return myList ?? null;
&lt;/pre&gt;
Much more elegant, n'est pas?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-9003415094067400802?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/9003415094067400802/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2009/04/c-operator.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/9003415094067400802'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/9003415094067400802'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2009/04/c-operator.html' title='C# ?? Operator'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_cuJk5OBwokQ/Se4hJt4UZ9I/AAAAAAAAAMg/l4NbqZC8H3w/s72-c/question.jpeg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-6693390174486105227</id><published>2009-04-10T12:52:00.000-04:00</published><updated>2009-04-10T12:53:58.695-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Sorting Algorithms</title><content type='html'>I stumbled across this great &lt;a href="http://www.sorting-algorithms.com/"&gt;animated comparison of sorting algorithms &lt;/a&gt;this afternoon.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-6693390174486105227?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/6693390174486105227/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2009/04/sorting-algorithms.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/6693390174486105227'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/6693390174486105227'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2009/04/sorting-algorithms.html' title='Sorting Algorithms'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-1753141336648857727</id><published>2009-04-03T09:38:00.002-04:00</published><updated>2009-04-03T09:40:00.676-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sf'/><title type='text'>Kirk</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_cuJk5OBwokQ/SdYRfv3r3fI/AAAAAAAAAMQ/lCGHkM4wQag/s1600-h/Kirk_awesome.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 506px; height: 372px;" src="http://2.bp.blogspot.com/_cuJk5OBwokQ/SdYRfv3r3fI/AAAAAAAAAMQ/lCGHkM4wQag/s320/Kirk_awesome.jpg" alt="" id="BLOGGER_PHOTO_ID_5320459246908464626" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-1753141336648857727?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/1753141336648857727/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2009/04/kirk.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/1753141336648857727'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/1753141336648857727'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2009/04/kirk.html' title='Kirk'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_cuJk5OBwokQ/SdYRfv3r3fI/AAAAAAAAAMQ/lCGHkM4wQag/s72-c/Kirk_awesome.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-553002514181691262</id><published>2009-03-30T09:49:00.002-04:00</published><updated>2009-03-30T09:54:25.223-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='computers'/><title type='text'>Mac Air Netbook Rumor</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_cuJk5OBwokQ/SdDOL_u2CoI/AAAAAAAAAMA/b3Q8lwTn_AE/s1600-h/1238371178184.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 291px;" src="http://4.bp.blogspot.com/_cuJk5OBwokQ/SdDOL_u2CoI/AAAAAAAAAMA/b3Q8lwTn_AE/s320/1238371178184.jpg" alt="" id="BLOGGER_PHOTO_ID_5318977865406352002" border="0" /&gt;&lt;/a&gt;&lt;a href="http://eeepc.net/apple-macbook-air-mini-leaked-apples-own-netbook/"&gt;If this is true&lt;/a&gt;, then I will make it the first Apple I have owned since the &lt;a href="http://en.wikipedia.org/wiki/Apple_II_series"&gt;Apple ][&lt;/a&gt;.

I just wanted to warn the wife.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-553002514181691262?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/553002514181691262/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2009/03/mac-air-netbook-rumor.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/553002514181691262'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/553002514181691262'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2009/03/mac-air-netbook-rumor.html' title='Mac Air Netbook Rumor'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_cuJk5OBwokQ/SdDOL_u2CoI/AAAAAAAAAMA/b3Q8lwTn_AE/s72-c/1238371178184.jpg' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-9077143347003586920</id><published>2009-03-26T09:34:00.006-04:00</published><updated>2009-03-26T15:49:46.714-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Matching</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_cuJk5OBwokQ/ScuEff7Rk-I/AAAAAAAAAL4/bu92az5Gyio/s1600-h/mmoriginal.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 143px; height: 320px;" src="http://4.bp.blogspot.com/_cuJk5OBwokQ/ScuEff7Rk-I/AAAAAAAAAL4/bu92az5Gyio/s320/mmoriginal.jpg" alt="" id="BLOGGER_PHOTO_ID_5317489461721928674" border="0" /&gt;&lt;/a&gt;I'm attempting to retrofit some test-driven-development concepts to a project I'm working on.  One of the first things I discovered was I had neglected to consider the concept of equality in my data classes.

I use classes with nested collections to move data around, but I hadn't written any code to test the collections for equality.  After some head-scratching and playing-around, I decided to use the IEquatable interface in the base type so I could pass a strongly-typed object to a .Equals method.  Here's an example:
&lt;pre&gt;
class Monkey: IEquatable&lt;monkey&gt;
{
   public string Name { get; set; }
   public int Bananas { get; set; }

   // IEquatable implementation
   public bool Equals(Monkey other)
   {
       return (other.Name == Name &amp;amp;&amp;amp; other.Bananas == Bananas);
   }
}
&lt;/monkey&gt;&lt;/pre&gt;If I had used the IComparable, I would have to test the type of the object before I test it for equality.  This is where the new features of C#, even since 2.0, really stand out and make things easier.  If you're still working on the 1.1 version of the framework, your life sucks.

Let's make some monkeys and some lists.&lt;pre&gt;       var Bonzo = new Monkey {Name = "Bonzo", Bananas = 7};
       var Bobo = new Monkey {Name = "Bobo", Bananas = 16};

       // make some groups
       var group1 = new List&lt;monkey&gt; { Bonzo, Bobo };
       var group2 = new List&lt;monkey&gt; { Bonzo, Bobo };          // matches group1
&lt;/monkey&gt;&lt;/monkey&gt;&lt;/pre&gt;In reality, you may not have to worry about duplicate list members when you're working with a database.  Or you may choose to use a hashtable that prevents duplicate entries. 

Here's how I decided to test for set value equality: First of all, if the numbers of elements in the two sets don't match, there's no way they have equal value.  Once that's out of the way, we just test to make sure all of the elements of the first set are in the second set.  If the sets pass both tests, they are equal, as far as my app is concerned.

There are actually three ways to determine that group1 matches group2.  Here they are in ascending order of coolness.&lt;pre&gt;Console.WriteLine(group1.Count == group2.Count &amp;amp;&amp;amp; group1.TrueForAll(m =&gt; group2.Contains(m)));
&lt;/pre&gt;This method leverages the extension method for generic lists that tests if a given predicate is true for all members of the set.  I used a lambda expression that will test all members of group1, m, are present in group2.

After I wrote that statement, ReSharper woke up and suggested I change it to this:&lt;pre&gt;Console.WriteLine(group1.Count == group2.Count &amp;amp;&amp;amp; group1.TrueForAll(group2.Contains));
&lt;/pre&gt;ReSharper called this "convert to &lt;a href="http://en.csharp-online.net/ECMA-334:_14.5.10.3_Delegate_creation_expressions"&gt;method group&lt;/a&gt;".  I guess since the elements of both groups are monkeys, and Contains takes a single monkey as an argument, it's obvious that the name of the method is all we need here?

The last way I tested this was at the suggestion of my cow-orker, Jeff.  He suggested importing the LINQ library and stepping up from IList&lt;t&gt; to IEnumberable&lt;t&gt; with the use of the All extension.&lt;pre&gt;Console.WriteLine(group1.Count == group2.Count &amp;amp;&amp;amp; group1.All(group2.Contains));
&lt;/pre&gt;Since IList&lt;t&gt; implements IEnumerable&lt;t&gt;, this steps the code up the evolutionary tree and may make it a little more bulletproof.

Now that I have the equality problem licked, I can get to writing some unit tests.  I should have done this on the first day!
&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-9077143347003586920?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/9077143347003586920/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2009/03/matching.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/9077143347003586920'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/9077143347003586920'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2009/03/matching.html' title='Matching'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_cuJk5OBwokQ/ScuEff7Rk-I/AAAAAAAAAL4/bu92az5Gyio/s72-c/mmoriginal.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-7772559440117596519</id><published>2009-03-20T15:31:00.003-04:00</published><updated>2009-03-20T15:37:48.519-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>We got the Func&lt;&gt;</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_cuJk5OBwokQ/ScPwejJKaLI/AAAAAAAAALw/OP5ZWp4zHxE/s1600-h/james+brown+09jpg.jpg"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 216px; height: 320px;" src="http://2.bp.blogspot.com/_cuJk5OBwokQ/ScPwejJKaLI/AAAAAAAAALw/OP5ZWp4zHxE/s320/james+brown+09jpg.jpg" alt="" id="BLOGGER_PHOTO_ID_5315356392847730866" border="0" /&gt;&lt;/a&gt;Another keyword in C# that always takes me by surprise is Func.

To know what Func&lt;&gt; is for, we have to know what delegates are for.  Delegates are a way to declare a function instance as a variable and pass it around, or make a list out of a set of them.

Say we make a function that accepts a double as a parameter and returns a double.
&lt;pre&gt;
private double Square(double squareThis)
{
  return Math.Pow(squareThis, 2.0);
}
private double Cube(double cubeThis)
{
  return Math.Pow(cubeThis, 3.0);
}
&lt;/pre&gt;
Next, we declare a delegate type to carry them around.
&lt;pre&gt;
private delegate double MathFunc(double x);
&lt;/pre&gt;
Now, we can make a list of MathFunc delegates and execute them all in a loop.
&lt;pre&gt;
var FuncList = new List&lt;mathfunc&gt;
  {
      Square,
      Cube,
      x =&gt; x*10
  };
foreach (var func in FuncList)
{
  Console.WriteLine(func(3));
}
&lt;/mathfunc&gt;&lt;/pre&gt;
The last element is a lambda expression.  There's no need to define the function in advance with C# 3.0.

Now we can talk about the Func&lt;&gt;.  Specifying Func&lt;&gt; means you're using a generic delegate, so that you don't have to declare the delegate elsewhere.  The first type you specify between the brackets is the return type, and the rest are the parameter types.

This code does the same thing as the last block, but doesn't use the MathFunc delegate.  Func&lt;&gt; is the underlying type of the lambda expression.  It was created to make predicate lambda expressions possible in LINQ.
&lt;pre&gt;
var NewFuncList = new List&lt;func&gt;&lt;double, double=""&gt;&gt;
  {
      Square,
      x =&gt; x*8
  };
foreach (var func in NewFuncList)
{
  Console.WriteLine(func(4));
}
&lt;/double,&gt;&lt;/func&gt;&lt;/pre&gt;
Finally, Action&lt;&gt; is just a Func&lt;&gt; that doesn't have any return types, just parameters.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-7772559440117596519?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/7772559440117596519/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2009/03/we-got-func.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/7772559440117596519'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/7772559440117596519'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2009/03/we-got-func.html' title='We got the Func&lt;&gt;'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_cuJk5OBwokQ/ScPwejJKaLI/AAAAAAAAALw/OP5ZWp4zHxE/s72-c/james+brown+09jpg.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-7253294489714473369</id><published>2009-03-03T15:13:00.003-05:00</published><updated>2009-03-03T15:14:55.620-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>But Why?</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_cuJk5OBwokQ/Sa2Pa_DdiHI/AAAAAAAAALQ/WyKGiMbO_g8/s1600-h/thinker.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 123px; height: 164px;" src="http://4.bp.blogspot.com/_cuJk5OBwokQ/Sa2Pa_DdiHI/AAAAAAAAALQ/WyKGiMbO_g8/s320/thinker.jpg" alt="" id="BLOGGER_PHOTO_ID_5309057229505005682" border="0" /&gt;&lt;/a&gt;More C# thoughts.

&lt;span style="font-weight: bold;"&gt;Internal&lt;/span&gt;

Internal means only other code in your assembly can use the so-declared class.  Not namespace.  Not file.  But assembly.

That means you can swap Public and Internal all you want inside your project, even between namespaces.  As long as the project compiles down to one assembly file, it doesn't make a difference.

Where it makes a difference is when you need to get to the Internal class via a reference.  Say you're using a second project in the solution, or you're referencing an assembly you've already installed somewhere.  Your Internal types will be invisible.

If you have a Public type in there and you declare a method or property Internal, the compiler won't find it either. 

Why would you want to do this?  &lt;a href="http://stackoverflow.com/questions/165719/practical-usings-of-internal-keyword-in-c"&gt;Perhaps &lt;/a&gt;you want to make some utility methods, like unit testing stuff, you don't want the paying customer to use.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-7253294489714473369?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/7253294489714473369/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2009/03/but-why.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/7253294489714473369'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/7253294489714473369'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2009/03/but-why.html' title='But Why?'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_cuJk5OBwokQ/Sa2Pa_DdiHI/AAAAAAAAALQ/WyKGiMbO_g8/s72-c/thinker.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-128919914756325029</id><published>2009-03-02T14:46:00.005-05:00</published><updated>2009-03-26T15:50:02.004-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Protect me from what?</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_cuJk5OBwokQ/Saw4h_t4MCI/AAAAAAAAALI/-2vcb38hHAA/s1600-h/fright.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 78px; height: 107px;" src="http://2.bp.blogspot.com/_cuJk5OBwokQ/Saw4h_t4MCI/AAAAAAAAALI/-2vcb38hHAA/s320/fright.jpg" alt="" id="BLOGGER_PHOTO_ID_5308680217453670434" border="0" /&gt;&lt;/a&gt;This is is the second entry in my series about C# keywords that trip me up.

We all know what it means to declare something public or private.  If a class, method or field is marked as Public, then any other code in any other class has access to it.  If we mark one as Private, then it can on;y be accessed from inside the class where it is defined.

&lt;span style="font-weight: bold;"&gt;Protected&lt;/span&gt;
Protected means the method can be access from the type and any derived types.  Here's what will make you head explode on this one.  Running WhatAmI() in this code will return "I'm a Monkey base class."
&lt;pre&gt;
class Monkey
{
    public string Talk()
    {
        return WhatAmI();
    }

    protected string WhatAmI()
    {
        return "I am a Monkey base class.";
    }
}
class Chimp : Monkey
{
    public new string Talk()
    {
        return WhatAmI();
    }
}
&lt;/pre&gt;Change protected string WhatAmI() to private and this won't compile unless you remove the public new string WhatAmI() from Chimp.

However, add this to Chimp and it will compile and run the private method:
&lt;pre&gt; private string WhatAmI()
{
    return "I'm a Chimp, derived from Monkey.";
}
&lt;/pre&gt;So the reason your brain explodes is you're overriding the protected method without either using the terms "override" or "new".&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-128919914756325029?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/128919914756325029/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2009/03/protect-me-from-what.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/128919914756325029'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/128919914756325029'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2009/03/protect-me-from-what.html' title='Protect me from what?'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_cuJk5OBwokQ/Saw4h_t4MCI/AAAAAAAAALI/-2vcb38hHAA/s72-c/fright.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-9076576480238154437</id><published>2009-02-28T22:13:00.005-05:00</published><updated>2009-02-28T22:32:07.337-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sf'/><title type='text'>She'll do the Kessel Run in less than 12 parsecs</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_cuJk5OBwokQ/San93pWpFFI/AAAAAAAAAKw/bLm25Cj6w6I/s1600-h/melfalc.jpg"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 300px; height: 203px;" src="http://3.bp.blogspot.com/_cuJk5OBwokQ/San93pWpFFI/AAAAAAAAAKw/bLm25Cj6w6I/s320/melfalc.jpg" alt="" id="BLOGGER_PHOTO_ID_5308052768268293202" border="0" /&gt;&lt;/a&gt;The other day, this appeared on my doorstep.  Literally.

Turns out, my friend Puna dropped it off.  She dropped it off because it was in her office.  It was in her office because it had been left there, for me, by a mutual friend.  A friend who, unbenownst to me, appears to have read my short article about my obsession with the Millennium Falcon.

Furthermore, this friend, who I must confess, thanks to the Internet, knows more about me than I know about her, told me she had left a surprise for me to pick up.  At the time, I was chasing my 3-year-old across a crowded lobby.  I thanked her as nicely as I could, given my fragile radar-lock on my daughter, and moved on to meet my wife, who was waiting for me.

Next problem: I thought her name was spelled with a 'K' and not a 'C', and it had a lot more n's in it than I thought.

So when I read the note that my friend wrote with the puzzle, I didn't make the connection.  For about 20 minutes, I thought I had an Internet stalker who knew where my house was.  I didn't know Puna had dropped it off.  And I didn't know how the Falcon's donor's name was spelled.

That was funny.

Anyways, I'd like to thank my friend for the puzzle.  I'd also like to apologize: I intended to build this thing and take a picture of it for the blog.  But there's something like 800 pieces in this box, and that just isn't going to happen in a timely fashion.  But I look forward to building this, because the $800 Lego thing is&lt;span style="font-style: italic;"&gt; never&lt;/span&gt; going to happen.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-9076576480238154437?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/9076576480238154437/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2009/02/shell-do-kessel-run-in-less-that-12.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/9076576480238154437'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/9076576480238154437'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2009/02/shell-do-kessel-run-in-less-that-12.html' title='She&apos;ll do the Kessel Run in less than 12 parsecs'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_cuJk5OBwokQ/San93pWpFFI/AAAAAAAAAKw/bLm25Cj6w6I/s72-c/melfalc.jpg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-2946283866264942612</id><published>2009-02-26T11:23:00.001-05:00</published><updated>2009-02-26T11:24:25.606-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='computers'/><title type='text'>Google Translate</title><content type='html'>&lt;a href="http://translate.google.com"&gt;Google Translate&lt;/a&gt;

第二十四爱尔兰摇滚乐队封装我的肘部与香蕉蜡上周末。

means

&lt;span style="font-style:italic;"&gt;Twenty Irish rockers encapsulated my elbow with banana wax last weekend.&lt;/span&gt;

but when translated back to English, 

&lt;span style="font-style:italic;"&gt;24th Irish rock band package my elbow with banana wax last weekend.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-2946283866264942612?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/2946283866264942612/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2009/02/google-translate.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/2946283866264942612'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/2946283866264942612'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2009/02/google-translate.html' title='Google Translate'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-6264616356347668809</id><published>2009-02-23T14:02:00.006-05:00</published><updated>2009-11-06T15:28:22.790-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>C# Keywords: const and readonly</title><content type='html'>This is the first in a series of posts about certain C# keywords that irritate me.&lt;br /&gt;
&lt;br /&gt;
Programming in general can be irritating.  Stumbling over a keyword that you think you ought to know but don't: that's especially irritating.&lt;br /&gt;
&lt;br /&gt;
Having to look up the keyword again after you thought you already learned what it did: marvelously irritating.&lt;br /&gt;
&lt;br /&gt;
So: what's the difference between const and readonly?  &lt;span style="font-weight: bold;"&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-weight: bold;"&gt;const&lt;/span&gt;&lt;br /&gt;
Applies to the declaration of a field or local variable.  Means the value cannot be modified.  The modifier static is not allowed, because it is implied the constant value is static.  It will be the same for all instances of the class, or any static methods it might have.  &lt;span style="font-weight: bold;"&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-weight: bold;"&gt;readonly&lt;/span&gt;&lt;br /&gt;
Readonly fields can be set in their declarations, just like constants, but they can also be set in their constructors.  This allows them to act like &lt;span style="font-style: italic;"&gt;instance-level &lt;/span&gt;constants.  Here's how it will confuse you: you will see the "readonly" keyword, but then you'll see it getting set in the constructor and your brain will explode.&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;class Monkey
{
    readonly int _cageNumber;
    public Monkey(int cageNumber)
    {
        _cageNumber = cageNumber;
    }
}
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-6264616356347668809?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/6264616356347668809/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2009/02/c-keywords-const-and-readonly.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/6264616356347668809'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/6264616356347668809'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2009/02/c-keywords-const-and-readonly.html' title='C# Keywords: const and readonly'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-1816538555596854824</id><published>2009-02-10T11:18:00.003-05:00</published><updated>2009-02-10T11:21:56.126-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sf'/><title type='text'>Han Solo</title><content type='html'>&lt;div style="text-align: left;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_cuJk5OBwokQ/SZGpBxlX8UI/AAAAAAAAAKQ/a6j30DMZH6s/s1600-h/GavinAsHansSolo.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 320px; height: 240px;" src="http://2.bp.blogspot.com/_cuJk5OBwokQ/SZGpBxlX8UI/AAAAAAAAAKQ/a6j30DMZH6s/s320/GavinAsHansSolo.jpg" alt="" id="BLOGGER_PHOTO_ID_5301204084346843458" border="0" /&gt;&lt;/a&gt;Puna made this for me today.  I told her I didn't look like Han Solo in the pictures of &lt;a href="http://lifesignatures.wordpress.com/2009/02/10/ramopenheartsurgery/"&gt;her blog about me&lt;/a&gt;.  So she whipped this up right quick.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-1816538555596854824?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/1816538555596854824/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2009/02/han-solo.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/1816538555596854824'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/1816538555596854824'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2009/02/han-solo.html' title='Han Solo'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_cuJk5OBwokQ/SZGpBxlX8UI/AAAAAAAAAKQ/a6j30DMZH6s/s72-c/GavinAsHansSolo.jpg' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-8335828031456187832</id><published>2009-02-06T15:53:00.004-05:00</published><updated>2009-03-26T15:50:34.745-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='computers'/><title type='text'>MS Word Sucks</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_cuJk5OBwokQ/SYyjhgPeJgI/AAAAAAAAAKI/-UnsU3Nlyzc/s1600-h/word2.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 301px; height: 320px;" src="http://3.bp.blogspot.com/_cuJk5OBwokQ/SYyjhgPeJgI/AAAAAAAAAKI/-UnsU3Nlyzc/s320/word2.jpg" alt="" id="BLOGGER_PHOTO_ID_5299790657494066690" border="0" /&gt;&lt;/a&gt;Microsoft Word made me so angry today, I sent this email to my supervisor.

&lt;span style="font-style: italic;"&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="font-style: italic;"&gt;I am going to stop using MS Word now.  &lt;/span&gt;

&lt;span style="font-style: italic;"&gt;I have spent the last 60 minutes working on use cases.  I have spent 55 of those minutes trying to get the little formatting and indenting and numbering right.  Boldface.  Italics.  Font size.  Indented sub-numbers.  &lt;/span&gt;

&lt;span style="font-style: italic;"&gt;I am going to leverage the fact that I have a dedicated, talented and helpful documentation specialist, so that I may firmly shake off the rusty shackles of MS Word for this project once and for all.&lt;/span&gt;

&lt;span style="font-style: italic;"&gt;I shall write my contributions with a text editor and allow you, Jacquelyn, to beautify and insert my contributions into our documentation.&lt;/span&gt;

&lt;span style="font-style: italic;"&gt;I hate MS Word.  Hate it.  Hate it.  Hate it.  Never before, in the endeavors of software development, has a program so effectively wasted my time.  &lt;/span&gt;

&lt;span style="font-style: italic;"&gt;Goodbye, cruel Word.&lt;/span&gt;&lt;/blockquote&gt;

I have begun to use GVIM with the spellchecker option turned on instead and it's much, much better.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-8335828031456187832?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/8335828031456187832/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2009/02/ms-word-sucks.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/8335828031456187832'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/8335828031456187832'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2009/02/ms-word-sucks.html' title='MS Word Sucks'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_cuJk5OBwokQ/SYyjhgPeJgI/AAAAAAAAAKI/-UnsU3Nlyzc/s72-c/word2.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-3047419010524308230</id><published>2009-02-02T20:45:00.003-05:00</published><updated>2009-02-02T20:54:50.286-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='computers'/><title type='text'>More information on the Z505</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_cuJk5OBwokQ/SYeh7Vso6-I/AAAAAAAAAJo/vnT6EryEp2Q/s1600-h/vaio_z505_profilethumb.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 200px; height: 203px;" src="http://3.bp.blogspot.com/_cuJk5OBwokQ/SYeh7Vso6-I/AAAAAAAAAJo/vnT6EryEp2Q/s320/vaio_z505_profilethumb.jpg" alt="" id="BLOGGER_PHOTO_ID_5298381527433407458" border="0" /&gt;&lt;/a&gt;
I got a few questions about what, exactly, I had to do to my Sony Z505 to get Xubuntu to install on it.  I wanted to reply to the commenters, but there was no email address.  So I thought I'd just make a follow-up post and edit the original document.  I've gotten a lot of responses to it.

This is exactly what I did to get it to work.

First, I downloaded the 8.04.1 version of Xubuntu.  I own the PCMCIA CD-ROM unit that came with it.  When you insert the PCMCIA card at the end of the cable, the PC will boot directly to the CDROM.  This is handy for restoring the backup operating system.

Naturally, the Sony booted to the Xubuntu disk.  I chose English as my language.  Then I pressed F6 for the "other options" menu.  Using the space bar, I marked acpi=off, noapic, and nolapic.

Then I was able to install and boot normally.

I wish I could tell you what those options mean.  I knew ACPI was supposed to be turned off for older machines, like this one.  I remember I spotted something about the other two options when I was searching the Net for some help. 

But that was all I had to do.  Thanks for all the comments.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-3047419010524308230?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/3047419010524308230/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2009/02/more-information-on-z505.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/3047419010524308230'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/3047419010524308230'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2009/02/more-information-on-z505.html' title='More information on the Z505'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_cuJk5OBwokQ/SYeh7Vso6-I/AAAAAAAAAJo/vnT6EryEp2Q/s72-c/vaio_z505_profilethumb.jpg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-7917436835337240845</id><published>2009-01-16T08:47:00.002-05:00</published><updated>2009-01-16T09:02:38.212-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='computers'/><title type='text'>Firefox and Wikipedia are Rad</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_cuJk5OBwokQ/SXCQx1zu_1I/AAAAAAAAAJU/VDNlB17xuN4/s1600-h/wikipedia-logo.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 151px; height: 182px;" src="http://4.bp.blogspot.com/_cuJk5OBwokQ/SXCQx1zu_1I/AAAAAAAAAJU/VDNlB17xuN4/s320/wikipedia-logo.jpg" alt="" id="BLOGGER_PHOTO_ID_5291888748092391250" border="0" /&gt;&lt;/a&gt;When I'm reading something online, and I come across a term I don't understand, I like to be able to read about it.  When I'm using Firefox, I can open a new tab, jump to wikipedia, look it up, then continue reading the original article.

I also noticed I can highlight a word, right click on it, and select "search google for".  The search opens in a new tab.

Finally, I can add wikipedia to the default search engine in the little search box on the upper-right of the browser.  This I knew.  But what I didn't know was the default search engine for the search box is also the one in the right-click menu.

Now, add all these little features up:

1. Change the search engine to wikipedia.
2. Right click on any given word or phrase
3. Search wikipedia and show result in new tab.

Bam.  Firefox completely defeats IE as my preferred browser.  All because of the combination of this little right-click feature and the default search engine.  Outstanding.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-7917436835337240845?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/7917436835337240845/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2009/01/firefox-and-wikipedia-are-rad.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/7917436835337240845'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/7917436835337240845'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2009/01/firefox-and-wikipedia-are-rad.html' title='Firefox and Wikipedia are Rad'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_cuJk5OBwokQ/SXCQx1zu_1I/AAAAAAAAAJU/VDNlB17xuN4/s72-c/wikipedia-logo.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-4316092010063919958</id><published>2008-12-31T15:44:00.003-05:00</published><updated>2009-11-06T15:23:31.840-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Windows Workflow Hurts</title><content type='html'>Windows Workflow Foundation (WF) has a lot of potential, but a combination of small pitfalls ruins it as a solution for all but the most stubborn of application architects.&lt;br /&gt;
&lt;br /&gt;
What initially interested me in WF was the opportunity to leverage the code behind SharePoint workflows to perform long-running tasks in my application.  I thought I could stitch together some activities that would watch tables in my database and perform actions as effects of state changes.  There was a significant learning curve to understand the role of the activities in the workflow class and the hosting environment, but I had a good book to help me through tutorials.  I got something working fairly easily.  Then I put off worrying about the finer details until I got farther along in my design.  &lt;span style="font-weight: bold;"&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-weight: bold;"&gt;WCF Integration and Statelessness&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
It was the finer details that caused my problems.  To begin with, there was the issue of communicating with the workflow class.  It was simple enough to make a command-line program that created the runtime environment and commanded it to make a new instance of the workflow.  You can communicate with the workflow by setting public properties of its class or by registering delegates to call-back events.  But I wanted to make this a web service.  There are two ways to make your workflow into a web service.  The first way is to add an activity called a WebServiceInput.  (I must point out here that I thought it was strange that I had to add a class to the workflow to enable it for SOAP.  I thought I would be changing something about the workflow hosting class.)&lt;br /&gt;
&lt;br /&gt;
After you add and configure the WebServiceInput class to the workflow, you can magically right-click on the project and choose “Publish as web service” from the context list.  The IDE will make a new project for you that re-implements the workflow as a regular, ASMX-style web service.  My workflow was simple: just wait x minutes and send a reminder to the assignee of the task.  When the assignment is complete, break the loop and end.  Calling this service, however, was very problematic because the autogenerated code assumed the service call was intended to be stateful.  Even when I used the asynchronous version of the web service call, I still got a timeout error from the service it created.  My app wasn’t going to continue until the workflow stopped.  After more research, I figured out the second way to implement the workflow as a web service was to use the ReceiveActivity that only comes in the .NET 3.5 framework.  Adding this activity causes the workflow to act like a WCF service.  It took a lot of work to figure out how to publish this service, though.&lt;br /&gt;
&lt;br /&gt;
WCF services are intended to be hosted by a WCF host application that doesn’t ship until Windows Server 2008.  This server also includes IIS 7.  If you set up the workflow in Visual Studio 2008 and use the right references, the studio will host your code in a junior version of the hosting program.  But when you want to run it in IIS, you have to make your own web.config.&lt;br /&gt;
&lt;br /&gt;
After hours of hair-pulling, I figured out the way to make it is to simply copy the app.config to web.config.  You also have to write an SVC file that contains the right tags so the service will be available through IIS.  &lt;span style="font-weight: bold;"&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-weight: bold;"&gt;Persistence and Statefulness&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Now I had a stateless workflow running, but when I tried to configure the web.config file with the persistence database XML entries, the config file wouldn’t validate and I couldn’t get the workflow to persist to the database.  When I tried this with the stateful version, it worked.   Now I was in a position to have to choose between stateful with persistence and stateless without persistence.  Clearly the idea of this workflow engine was becoming more trouble than it was worth.  But it was another problem that convinced me to drop the persistence goal.&lt;br /&gt;
&lt;span style="font-weight: bold;"&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-weight: bold;"&gt;Upgrading Workflow Logic&lt;/span&gt;  I learned when the workflow engine gets upgraded with a new version of the DLL, the persisted workflows may no longer function properly.  In order to update an idled workflow, you have to use a WorkflowChanges class, pass in the root activity, update the TransientActivities class… what a mess!  This was becoming much too complicated just for pounding out a little business logic with a cool designer.   &lt;span style="font-weight: bold;"&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-weight: bold;"&gt;The Next Version&lt;/span&gt;  I found out there is a new version of workflow coming with the next framework that will do away with activities altogether.  I’m guessing the designers are going to try to make this process a little simpler, but one thing I did read quite clearly was all existing workflows would have to be rewritten for the new host.  So as far as I’m concerned, that seals workflow’s fate for me in the 3.5 framework.   &lt;span style="font-weight: bold;"&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-weight: bold;"&gt;My Solution: Abandon Ship&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
I’m going to roll with a stateless, WCF reminder service that does not persist to a database.  I’m going to write a helper app that references the service and “wakes up” all the reminder threads in the event the system is restarted.  I’m not going to connect the host to a database, which also removes some security concerns for me.  And I’ll keep business logic in our plain-old business-layer classes.  I’m going to put WF out of my mind for a very long time.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-4316092010063919958?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/4316092010063919958/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2008/12/windows-workflow-hurts.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/4316092010063919958'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/4316092010063919958'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2008/12/windows-workflow-hurts.html' title='Windows Workflow Hurts'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-8139392244713904142</id><published>2008-12-05T15:59:00.003-05:00</published><updated>2008-12-05T16:07:04.741-05:00</updated><title type='text'>Speech Synthesis in Iron Python</title><content type='html'>&lt;p align="left"&gt;&lt;a href="http://4.bp.blogspot.com/_cuJk5OBwokQ/STmXWBM0oBI/AAAAAAAAAJM/an3B7pnT4WY/s1600-h/robot.jpg"&gt;&lt;img id="BLOGGER_PHOTO_ID_5276414842976378898" style="DISPLAY: block; MARGIN: 0px auto 10px; WIDTH: 88px; CURSOR: hand; HEIGHT: 134px; TEXT-ALIGN: center" alt="" src="http://4.bp.blogspot.com/_cuJk5OBwokQ/STmXWBM0oBI/AAAAAAAAAJM/an3B7pnT4WY/s320/robot.jpg" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;This is how we programmers waste time at the office. &lt;/p&gt;&lt;ol&gt;&lt;li&gt;Open ipy.exe.&lt;/li&gt;&lt;li&gt;import sys&lt;/li&gt;&lt;li&gt;import clr&lt;/li&gt;&lt;li&gt;clr.AddReference("System.Speech")&lt;/li&gt;&lt;li&gt;import System&lt;/li&gt;&lt;li&gt;s = System.Speech.Synthesis.SpeechSynthesizer()&lt;/li&gt;&lt;li&gt;s.Speak("How much do we pay you for this?")&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/8772123162990273002-8139392244713904142?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/8139392244713904142/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2008/12/speech-synthesis-in-iron-python.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/8139392244713904142'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/8139392244713904142'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2008/12/speech-synthesis-in-iron-python.html' title='Speech Synthesis in Iron Python'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_cuJk5OBwokQ/STmXWBM0oBI/AAAAAAAAAJM/an3B7pnT4WY/s72-c/robot.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-4809675495324378632</id><published>2008-12-04T09:21:00.002-05:00</published><updated>2008-12-04T09:25:41.463-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sf'/><title type='text'>Legos are rad</title><content type='html'>&lt;a href="http://1.bp.blogspot.com/_cuJk5OBwokQ/STfoU5kA_rI/AAAAAAAAAI8/1kELZVsnDR8/s1600-h/mf.jpg"&gt;&lt;img id="BLOGGER_PHOTO_ID_5275940934234734258" style="DISPLAY: block; MARGIN: 0px auto 10px; WIDTH: 280px; CURSOR: hand; HEIGHT: 280px; TEXT-ALIGN: center" alt="" src="http://1.bp.blogspot.com/_cuJk5OBwokQ/STfoU5kA_rI/AAAAAAAAAI8/1kELZVsnDR8/s320/mf.jpg" border="0" /&gt;&lt;/a&gt;
&lt;div&gt;&lt;a href="http://www.amazon.com/LEGO-Ultimate-Collectors-Millennium-Falcon/dp/B000WLW3W0/"&gt;This &lt;/a&gt;is the coolest thing I have ever seen. This showed up in my Amazon spam this morning. It is ridiculously expensive. If I had gotten something like this on Christmas morning, I would have lost control of my bladder. Heck, I think I would lose control of my bladder if I got this today. &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-4809675495324378632?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/4809675495324378632/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2008/12/legos-are-rad.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/4809675495324378632'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/4809675495324378632'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2008/12/legos-are-rad.html' title='Legos are rad'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_cuJk5OBwokQ/STfoU5kA_rI/AAAAAAAAAI8/1kELZVsnDR8/s72-c/mf.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-3566097543255204465</id><published>2008-11-17T20:40:00.003-05:00</published><updated>2008-11-18T07:50:55.541-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sf'/><title type='text'>New Star Trek Movie</title><content type='html'>&lt;a href="http://www.apple.com/trailers/paramount/startrek/large_trailer2.html"&gt;The new trailer is out.&lt;/a&gt;  

People ask me what my favorite trek show or movie was.  I have always liked the original series the best, and Wrath of Khan.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-3566097543255204465?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/3566097543255204465/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2008/11/new-star-trek-movie.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/3566097543255204465'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/3566097543255204465'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2008/11/new-star-trek-movie.html' title='New Star Trek Movie'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-2868999750206236903</id><published>2008-11-15T22:28:00.002-05:00</published><updated>2008-11-15T22:38:15.573-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='beer'/><title type='text'>Troegenator Double Bock</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_cuJk5OBwokQ/SR-TlCuT9iI/AAAAAAAAAI0/NnMxQRYdDPk/s1600-h/Troegenator+with+glass+web+200.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 230px; height: 320px;" src="http://1.bp.blogspot.com/_cuJk5OBwokQ/SR-TlCuT9iI/AAAAAAAAAI0/NnMxQRYdDPk/s320/Troegenator+with+glass+web+200.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5269092353642329634" /&gt;&lt;/a&gt;
I bought a pack of this stuff last month and I was pleasantly surprised at how good it tastes.  It has a similar spicy flavor as the Raison d'Etre I blogged about last month, but it's a little lighter and easier to drink.  I give it four out of five Gavins.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-2868999750206236903?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/2868999750206236903/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2008/11/troegenator-double-bock.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/2868999750206236903'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/2868999750206236903'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2008/11/troegenator-double-bock.html' title='Troegenator Double Bock'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_cuJk5OBwokQ/SR-TlCuT9iI/AAAAAAAAAI0/NnMxQRYdDPk/s72-c/Troegenator+with+glass+web+200.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-1417663053523147340</id><published>2008-11-13T15:43:00.003-05:00</published><updated>2008-11-13T15:50:35.547-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>MVC: Don't try it with IIS 6.0</title><content type='html'>So nowhere in the happy-fun blog posts, which are the only way to learn how it works, are there any warnings that say: "Don't bother to try to deploy your shiny, new MVC ASP.NET application to IIS 6.0!"  

If you don't use IIS 7, you're in trouble.  You can't route to the controllers and views you've written because IIS 6 doesn't support the same ISAPI filter.  You have to either write your own ISAPI filter, or change your routing table to stick ".mvc" between the controller and the view.  &lt;a href="http://stackoverflow.com/questions/34194/aspnet-mvc-on-iis6"&gt;StackOverflow &lt;/a&gt; has a nice page on this.

Either way, you break your source code for debugging it in the IDE.  Which defeats the purpose of trying to keep things simple by using MVC.

I feel like I've been ripped off.  I have (re?) learned a valuable lesson today: don't use beta code for something you're on the hook for.  Fortunately for me, the hook was pretty small and I only have to write three or four pages in regular webforms to make up for the damage.  I'm not going to mess with this.  

Curse you, MVC!  Vile temptress!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-1417663053523147340?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/1417663053523147340/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2008/11/mvc-dont-try-it-with-iis-60.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/1417663053523147340'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/1417663053523147340'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2008/11/mvc-dont-try-it-with-iis-60.html' title='MVC: Don&apos;t try it with IIS 6.0'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-6957622096666383549</id><published>2008-11-12T15:27:00.006-05:00</published><updated>2008-11-12T15:35:38.805-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>WCF Library-to-Application conversion</title><content type='html'>&lt;strong&gt;Update!&lt;/strong&gt; You can transmogrify a WCF Service &lt;strong&gt;Library&lt;/strong&gt; to a WCF Service &lt;strong&gt;Application&lt;/strong&gt; if you do these things:
&lt;ol&gt;&lt;li&gt;Make a web.config file. Copy the app.config file contents into it.&lt;/li&gt;&lt;li&gt;Make an SVC file manually. Make the first line of the file %@ ServiceHost Language="C#" Debug="true" Service="myNamespace.Service1" &lt;/li&gt;&lt;li&gt;Change the configuration of the project to make it's DLL in the bin directory and not the /bin/Debug directory.&lt;/li&gt;&lt;li&gt;Deploy the bin, svc and web.config files to a virtual directory. Browse to the svc file and behold your WSDL. This worked for me in IIS 6.&lt;/li&gt;&lt;li&gt;Profit.&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/8772123162990273002-6957622096666383549?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/6957622096666383549/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2008/11/wcf-library-to-application-conversion.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/6957622096666383549'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/6957622096666383549'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2008/11/wcf-library-to-application-conversion.html' title='WCF Library-to-Application conversion'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-2402343936987395870</id><published>2008-11-12T13:25:00.003-05:00</published><updated>2009-11-06T15:25:36.266-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>WCF: Webserver Configuration Fubar</title><content type='html'>&lt;a href="http://4.bp.blogspot.com/_cuJk5OBwokQ/SRsf9RwtusI/AAAAAAAAAIs/Ki9CaXoK30Y/s1600-h/wcf2.jpg"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5267839326740134594" src="http://4.bp.blogspot.com/_cuJk5OBwokQ/SRsf9RwtusI/AAAAAAAAAIs/Ki9CaXoK30Y/s320/wcf2.jpg" style="display: block; height: 225px; margin: 0px auto 10px; text-align: center; width: 320px;" /&gt;&lt;/a&gt; &lt;br /&gt;
&lt;div&gt;&lt;/div&gt;&lt;div&gt;OK, so I'll admit that my problem was I wrote a WCF Service Library instead of a WCF Service Application.&lt;br /&gt;
&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;If you want to write a WCF webservice, in Visual Studio, after you click New Project, you choose Web from the project types and WCF Application as the template. This will create a nice little template application for you that includes a web.config file and an SVC file. The SVC serves the same purpose as the ASMX file for old-skule services. You deploy the files and the bin directory and you're working. &lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
What I (idiot) did was create a WCF Service Library. It still sets up an interface and an implementation class, but what it does differently is this: It doens't make an SVC file or a web.config. That's because it lives to be hosted by something else. What is the something else? In Visual Studio 2008 it's the WCFServiceHost application. When you search for service references from other projects in the solution, or test the library, it just works. How nice. In Windows Server 2008 this host app ships. In Server 2003, it does not. Which means you can write an app that works one way on your local box but doesn't work on your servers. &lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
Why did they do this to me? Apparently, since I can "bind" the service to different "endpoints" I'm not limited to using IIS anymore. I could bind it to FTP, for example. I have trouble seeing the benefit to this, yet.&lt;br /&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-2402343936987395870?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/2402343936987395870/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2008/11/wcf-webserver-configuration-fubar_12.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/2402343936987395870'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/2402343936987395870'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2008/11/wcf-webserver-configuration-fubar_12.html' title='WCF: Webserver Configuration Fubar'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_cuJk5OBwokQ/SRsf9RwtusI/AAAAAAAAAIs/Ki9CaXoK30Y/s72-c/wcf2.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-111802694839907788</id><published>2008-11-12T08:11:00.003-05:00</published><updated>2009-11-06T15:21:29.599-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>WCF: Windows Confusion Foundation</title><content type='html'>&lt;a href="http://3.bp.blogspot.com/_cuJk5OBwokQ/SRrXfz1bUJI/AAAAAAAAAIc/ebP4H7EaN8Y/s1600-h/wcf.jpg"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5267759655653429394" src="http://3.bp.blogspot.com/_cuJk5OBwokQ/SRrXfz1bUJI/AAAAAAAAAIc/ebP4H7EaN8Y/s320/wcf.jpg" style="display: block; height: 225px; margin: 0px auto 10px; text-align: center; width: 320px;" /&gt;&lt;/a&gt; WCF: Let's take ASMX web services, that worked really well and were simple to deploy, and turn it into something allegedly does the same thing with a different back-end.  Then, we'll program Visual Studio to produce artifacts that won't simply deploy and just work to IIS.  Finally, in order to kick you while you're down, we'll completely do away with any deployment tools and make you hunt on the Internet for blog postings, written by someone you may not want to trust, to get a &lt;i&gt;hint&lt;/i&gt; about what to search for in the MSDN to figure out how to deploy one.&lt;br /&gt;
&lt;br /&gt;
And if that's not enough, we'll tout WCF as the wave of the future and make you feel like a complete anachronistic fool if you try to code anything else.&lt;br /&gt;
&lt;br /&gt;
Meanwhile, all the serious developers and throwing out SOAP requests in favor of RESTful web services, which make a hell of a lot more sense.  That's when you realize that the translation of "wsHttpBinding" is... wait for it... SOAP!  So you're wasting hours trying to relearn how to deploy something that behaves exactly like what you already knew how to write.&lt;br /&gt;
&lt;br /&gt;
WCF, I would spit on you, but I like my DoubleSight LCD panels too much.  I will spit on you when I get home to my old 17-inch CRT.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-111802694839907788?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/111802694839907788/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2008/11/wcf-windows-confusion-foundation.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/111802694839907788'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/111802694839907788'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2008/11/wcf-windows-confusion-foundation.html' title='WCF: Windows Confusion Foundation'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_cuJk5OBwokQ/SRrXfz1bUJI/AAAAAAAAAIc/ebP4H7EaN8Y/s72-c/wcf.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-6240714377233418546</id><published>2008-11-10T22:13:00.007-05:00</published><updated>2008-11-11T06:06:15.695-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='beer'/><title type='text'>Magic beer dispenser</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_cuJk5OBwokQ/SRj6qT2WfqI/AAAAAAAAAIU/OaK3zFhasKo/s1600-h/heineken-draught-keg-beer.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="http://2.bp.blogspot.com/_cuJk5OBwokQ/SRj6qT2WfqI/AAAAAAAAAIU/OaK3zFhasKo/s320/heineken-draught-keg-beer.jpg" alt="" id="BLOGGER_PHOTO_ID_5267235368999485090" border="0" /&gt;&lt;/a&gt;&lt;span&gt;Last Christmas, I decided I wanted to drink a lot of beer.  I had been eyeing the enormous mega-can of Groelsch at my local liquor store.  As I stood there, holding my pathetic, average six-pack of normal, everyday fine craft microbrews, I longed for what must be the endless wellspring of tasty goodness owning a mini-keg would bring.  On Christmas Eve, I surrendered to the urge to bring home that little castle of German beer. 

As it is with such things, the reality is so much different than the fantasy.  After drinking what must have been four thousand calories of beer, I was shocked to discover 1) I had a headache on Christmas morning and 2) there was still beer in there.  The headache would go away on its own, but the beer would need some help from me.

I know this may come as a shock to you. but I did not immediately begin to comsume the remaining beer.  In fact, I waited until the end of the week.  There are many reasons for this.  As a software developer, I am compelled to  explain the reasons in the form of a table:
&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;
Number of beers: &lt;/span&gt;One
&lt;span style="font-weight: bold;"&gt;Benefits&lt;/span&gt;: Children seem less irritating
&lt;span style="font-weight: bold;"&gt;Side Effects&lt;/span&gt;: No immediate effects, however, daily repetition leads to weight gain.

&lt;span style="font-weight: bold;"&gt;Number of Beers&lt;/span&gt;: Two
&lt;span style="font-weight: bold;"&gt;Benefits&lt;/span&gt;: Children-irritation &gt;= one beer, depending on circumstances.  Approaching drowsiness threshold.
&lt;span style="font-weight: bold;"&gt;Side Effects&lt;/span&gt;: Wife begins to get understandably concerned, possibly irritated.

&lt;span style="font-weight: bold;"&gt;Number of beers&lt;/span&gt;: Three
&lt;span style="font-weight: bold;"&gt;Benefits&lt;/span&gt;: Drowsiness threshold has been crossed, children magically vanish.
&lt;span style="font-weight: bold;"&gt;Side Effects&lt;/span&gt;: Probability of wife irritation approaches 1.  Headache ensues, immediate .25% weight gain.
&lt;p&gt;&lt;/p&gt;So I waited New Years' Eve to drink the next pint.  And when I poured the beer from the mini-keg, I made a terrible discovery.  During the time that had elapsed since Christmas, the beer had gone flat.  Not a single bubble ascended from the bottom of the glass, the beer a shadow of its former self.  I vowed never again to buy a giant can of beer.

Until now.

Earlier this month, a friend brought over a Heineken Draught Keg for a party I was throwing.  I thought "Uh-oh, once again, pints of beer will go to waste."  But there was something different about this can.  It had its own tap, not just a plug.  When you open the tap, advanced beer technology, sufficient enough to be indisiguishable from magic, charges the beer with CO2.  Each pint was bubbly and perfectly foamy.  Tasted like I had bought it in a pub.

"Whatever," I thought.  "In a few days, this will be toast.  Guess what?  seven days later and it still produces tap-quality beer!

My fellow beer-drinkers, I urge you to invest in a Draught Keg from Heineken.  The website says it will last for thirty days.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-6240714377233418546?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/6240714377233418546/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2008/11/magic-beer-dispenser.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/6240714377233418546'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/6240714377233418546'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2008/11/magic-beer-dispenser.html' title='Magic beer dispenser'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_cuJk5OBwokQ/SRj6qT2WfqI/AAAAAAAAAIU/OaK3zFhasKo/s72-c/heineken-draught-keg-beer.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-5168828402457538607</id><published>2008-11-08T07:39:00.007-05:00</published><updated>2009-12-30T08:29:41.257-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='computers'/><title type='text'>New Old Netbook</title><content type='html'>Let me tell you about my Sony Z505.  To be precise, it's s a Sony Z505 HE.  I bought this thing in 1999.  With the extra, high-capacity battery and the external CD-ROM, I spent well over $2000 on it.  It came with Windows 98!  It had a 450 mhz Pentium III processor, so it was the fastest machine in my arsenal at the time. &lt;a href="http://1.bp.blogspot.com/_cuJk5OBwokQ/SRWJIvBjheI/AAAAAAAAAHg/PqfPGa8cV1E/s1600-h/z505.jpg" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5266266122434610658" src="http://1.bp.blogspot.com/_cuJk5OBwokQ/SRWJIvBjheI/AAAAAAAAAHg/PqfPGa8cV1E/s320/z505.jpg" style="cursor: pointer; float: left; height: 216px; margin: 0pt 10px 10px 0pt; width: 320px;" /&gt;&lt;/a&gt;  It was fantastic.  It weighed less than four pounds, had a hefty eight-gigabyte hard drive, and 128 megabytes of RAM.  It was the ultimate development machine for VB6 and SQL Server 2000.  At the time, I was telecommutung every day.  I used the machine to hack code at coffee shops and such.  I loved using it.  I would have conversations at demos and job interviews about the machine.  I even heard the guys who worked for Slashdot were using them, so I thought I was pretty cool.&lt;br /&gt;
&lt;br /&gt;
Then, of course, it got old.  The gigahertz-processor-frequency barrier was broken.  Machines started coming with more RAM and large hard disks.  I tried to keep up.  I installed a new RAM module to increace the memory to 192 MB (the max for this model.)  I found a site online that showed me how to crack the case and put a new 2.5-inch disk inside.  When I did it, I broke the touchpad.  The batteries quit working.  I started doing all my work with Windows XP, which was too intense for the machine.  So eventually, I had a tiny, underpowered mini-laptop computer with no wireless, no batteries, and no touchpad.  That cost over $2500 to buy.  So I put it in a box in my storage room while I moved on to other things and forgot about it.&lt;br /&gt;
&lt;br /&gt;
Until a few things happened.  First, I got a new job.  To get to the new job, I had to ride a commuter bus for about 45 minutes each way.  So I suddenly got 90 minutes a day to spend with a computer.  I started bringing my Thinkpad with me.  But most of the time, it was just a little too large to see the screen.  I would throw it in my bag, take it on the bus, and hope I could get a seat where there would be enough room to open the thing.  I started working through Dive Into Python.  But half of the days of the week, I couldn't get the lid back far enough to see thing.  So I would cart around this eight-pound computer for nothing.&lt;br /&gt;
&lt;br /&gt;
Then, I discovered Linux.  Ubuntu to be precise, and Xubuntu to be really precise.  I had been spending my spare time going through all the old computers I had and installing Xubuntu to see if I could.  It wasn't very productive, but it was fun and didn't cost anything.  After my experience with the Z505, I was against spending much money on computers.  Don't get me wrong, I had bought a refurbished Thinkpad for grad school, and was happily running Ubuntu on that.  But the idea of plunking down much money for computers made me  think.  Xubuntu was working great on these older machines.  The only these old, revived Xubuntu machines couldn't do was 1) play Doom III, which I didn't play anyway since I got, like, trapped in Hell or something and my guns quit working and 2) play flash videos, like Youtube.  MSNBC news clips were the worst, but I could live without them.. I figured out that if I downloaded my favorite shows from Revision3 instead of watching the flash, it worked great.&lt;br /&gt;
&lt;br /&gt;
Finally, the netbook revolution happened.  Now this was cool.  For three hundred dollars, I could get a tiny Linux box that I could always open, see, and use, and only weighed about three pounds.  For that kind of weight, I didn't have to lug around a big, heavy, full-size machine to read, write and code for my 90 minute "alone time."  But there were a few things about these machines that bothered me.  First, I didn't like the tiny screens.  800-pixels wide was too small for me, and the larger screens came at the cost of screen height.  The machines ran Linux, but hold on, it was a crippleware-version of the OS, and, although it would do anything I probably wanted, including run Python and watch Youtube, it wasn't the real thing.  Ubuntu had released a special netbook "remix" version, but I didn't want to go through the hassle of trying to figure out how to install it without a CD-ROM, or have to buy one after my VAIO experience.&lt;br /&gt;
&lt;br /&gt;
But I couldn't help thinking abou the old Sony VAIO in my junkpile.  It had a fantastic 12-inch LCD, and I had an unused wireless-G card to stick in it.  It only weighed three pounds, too.  And, although it only had 192 MB of RAM, it should be able to do almost anything a netbook could do.  Why should I drop fifteen hundred dollars on a new computer that Microsoft would just invalidate in a few years?  That's not what computers are about for me.  For me, computers are about solving problems and learning new things.  I only want to spend money when my needs outpace the computer's abilities.  So I thought, why should I buy one of these underpowered little netbook computers when I already have one of my own?  Why can't I revive the Z505, buy a new battery, and install Linux on there?&lt;br /&gt;
&lt;br /&gt;
So I made a plan: If I could get a decent operating system on there, I'd buy a new battery and make it my new "bus warrior" netbook.  Although I had been using Xubuntu on some other machines, I decided to try some other "lightweight" operating systems first to see if I could get something that really peformed great.&lt;br /&gt;
&lt;br /&gt;
First, I tried Puppy Linux.  I couldn't get it to boot from the CD-ROM.  The CD-ROM on the VAIO works through the PCMCIA slot, and was, in fact, responsible for about $300 of the price of the machine.  You had to buy it separately if you wanted to use the system restore disk, which I had to do once.  Then I tried DSL.  I had to comb the Internet looking for how to get the thing to boot up.  Finally, I found a command switch to pass the boot loader.  I have no idea what it means:  DSL ide2=0x180, 0x386 acpi=off, nohotplug, nopcmcia  That worked pretty fast, but there were two problems.  It didn't set up my Linksys wireless-g network card.  I would have to use ndiswrapper to get that to work, and that would be a lot of feeling around in the dark.&lt;br /&gt;
&lt;br /&gt;
I also really, really missed Synaptic.  In fact, when I realized how much I missed Synaptic, I knew what I had to do.  I just went back to Xubuntu.  To get Xubuntu to boot, I had to turn ACPI off, and one or two other things in the advanced boot menu.  But it worked like a charm.  But after I installed it and restarted with the PCMCIA wireless card installed, it detected it and offered to install the (proprietary) driver.  Awesome!  So easy. &lt;a href="http://4.bp.blogspot.com/_cuJk5OBwokQ/SRWJv4kVNvI/AAAAAAAAAHo/fe2qJNsx2cw/s1600-h/pxubuntuwk6.th.png.jpeg" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5266266795011290866" src="http://4.bp.blogspot.com/_cuJk5OBwokQ/SRWJv4kVNvI/AAAAAAAAAHo/fe2qJNsx2cw/s320/pxubuntuwk6.th.png.jpeg" style="cursor: pointer; float: right; height: 150px; margin: 0pt 0pt 10px 10px; width: 119px;" /&gt;&lt;/a&gt; I bought a battery for it through Amazon for about $70 and I was finished.  Bam.  I've got a netbook for $70 with a 40 GB HDD.&lt;br /&gt;
&lt;br /&gt;
But I still have a few problems, though.  The USB port detected a USB flash drive, but it wouldn't detect my USB external disk.  I have to do some homework on that, because I wanted to copy my tunes on here.  I've always found USB devices to be flaky like that.  The battery appears to last long enough for a whole day's bus ride and a half-hour of remote use at home, which is just about right.  I might get more time out of it if I remove the wireless card and dim the LCD when I use it.  And the wireless connection strength seems to only read about 80% even when I'm right next to the wireless router, but that might not be a big deal.&lt;br /&gt;
&lt;br /&gt;
But that's how I got my netbook for $70.  Actually, I paid $2500 for it since 1999, but at least I didn't have to buy anything new.  And if it gets destroyed somehow, I won't be so upset.&lt;br /&gt;
&lt;br /&gt;
UPDATE: &lt;a href="http://invalidobject.blogspot.com/2009/02/more-information-on-z505.html"&gt;Here are the setting I made to get it to install&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-5168828402457538607?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/5168828402457538607/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2008/11/new-old-netbook.html#comment-form' title='40 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/5168828402457538607'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/5168828402457538607'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2008/11/new-old-netbook.html' title='New Old Netbook'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_cuJk5OBwokQ/SRWJIvBjheI/AAAAAAAAAHg/PqfPGa8cV1E/s72-c/z505.jpg' height='72' width='72'/><thr:total>40</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-8740143997910733996</id><published>2008-09-11T08:48:00.003-04:00</published><updated>2008-11-11T06:07:20.424-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='beer'/><title type='text'>Dogfish Head Raison D'Etre</title><content type='html'>&lt;a href="http://1.bp.blogspot.com/_cuJk5OBwokQ/SMkT0LWBRDI/AAAAAAAAAG4/mU7ooWj224s/s1600-h/beer1.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_cuJk5OBwokQ/SMkT0LWBRDI/AAAAAAAAAG4/mU7ooWj224s/s320/beer1.jpg" alt="" id="BLOGGER_PHOTO_ID_5244745028168926258" border="0" /&gt;&lt;/a&gt;
&lt;a href="http://www.dogfish.com/brewings/Year_Round_Beers/Raison_DEtre/7/index.htm"&gt;This&lt;/a&gt; has been my favorite beer for a while now.  You can really taste the rasins and brown sugar.  I must get around to acquiring a goblet at once.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-8740143997910733996?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/8740143997910733996/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2008/09/blog-post.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/8740143997910733996'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/8740143997910733996'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2008/09/blog-post.html' title='Dogfish Head Raison D&apos;Etre'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_cuJk5OBwokQ/SMkT0LWBRDI/AAAAAAAAAG4/mU7ooWj224s/s72-c/beer1.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-4592962572439681994</id><published>2008-09-10T11:44:00.004-04:00</published><updated>2008-11-11T06:10:13.071-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Sql Server Management Objects</title><content type='html'>&lt;a href="http://weblogs.asp.net/jgalloway/archive/2006/11/07/Handling-_2200_GO_2200_-Separators-in-SQL-Scripts-_2D00_-the-easy-way.aspx"&gt;This &lt;/a&gt;guy saved my butt today.

You can generate CREATE PROCEDURE scripts and the like very easily from SQL Server, but you can't read them back into strings and execute the commands from ADO because the GO directive is not considered "SQL". 

You could have stripped them out, but then any script you tried to run through the command object might not have worked as expected.  You could have shelled out to isql, but that's painful.  With SMO, it just works, as it should have already.  Bravo, Jon, and thanks.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-4592962572439681994?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/4592962572439681994/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2008/09/sql-server-management-objects.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/4592962572439681994'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/4592962572439681994'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2008/09/sql-server-management-objects.html' title='Sql Server Management Objects'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-7769154047880058717</id><published>2008-09-10T08:28:00.006-04:00</published><updated>2008-11-11T06:10:42.422-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sf'/><title type='text'>Great SF Story Idea</title><content type='html'>I don't usually repost news stories, but this morning I had an epiphany of nerd news stories combine in my head to form something greater than the sum of its parts.

A Harvard biologist &lt;a href="http://science.slashdot.org/science/08/09/09/2211216.shtml"&gt;creates artifical life &lt;/a&gt;in his lab, which mutates and threatens to &lt;a href="http://en.wikipedia.org/wiki/Grey_goo"&gt;destroy the human race&lt;/a&gt;.  But we &lt;a href="http://en.wikipedia.org/wiki/Technological_singularity"&gt;upload our brains &lt;/a&gt;into computer systems and &lt;a href="http://www.mahalo.com/Lhc"&gt;create a black hole &lt;/a&gt;that swallows the Earth before they can succeed with their plan.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-7769154047880058717?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/7769154047880058717/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2008/09/great-sf-story.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/7769154047880058717'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/7769154047880058717'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2008/09/great-sf-story.html' title='Great SF Story Idea'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-6341897841254762885</id><published>2008-09-05T07:54:00.004-04:00</published><updated>2008-11-11T06:12:31.726-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Visual Studio as a plain old text editor</title><content type='html'>I enjoy using GVIM as my general text editor.  I enjoy the syntax highlighting, the keyboard-centric approach, and the price -- free.

But here at my new job I'm not really allowed to install any new software.  I suppose I could ask to install GVIM, but I don't really want to cause a fuss to do something I can do with Notepad.

So I trudged along with Notepad, without line numbers and syntax highlighting and bookmarks and window splitting.  Sigh.

Until today, when I realized I can use Visual Studio as my plain-old text editor.  From the command line, rather than type &gt;GVIM blah.txt, or &gt;notepad blah.txt, I just use this command:

&gt; devenv blah.txt

Problem solved!  I have all the features of the Visual Studio editor without the solution and project and source control overhead!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-6341897841254762885?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/6341897841254762885/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2008/09/visual-studio-as-plain-old-text-editor.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/6341897841254762885'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/6341897841254762885'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2008/09/visual-studio-as-plain-old-text-editor.html' title='Visual Studio as a plain old text editor'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-4513760781403263093</id><published>2008-08-13T10:14:00.006-04:00</published><updated>2009-02-23T09:51:12.872-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Extension methods are rad</title><content type='html'>The point of extension methods is to let you tack on new methods to existing SEALED classes, rather than subclass them. You might also want to take a different approach from subclassing, when you want a bunch of objects in your toolset that are just a little different from the normal set. Apparently, deep subclass trees can get on people's nerves. With extension methods, you could define a static class in your namespace that just contains all the oddball extended methods. I can see the merit to that approach, especially when you want to have some special checks on strings, like specialized regex checks.

&lt;pre&gt;
namespace whatever.foobar
{
 public static class Extensions  // seemed like an obvious choice for the name
 {
 // Extension method for testing the validity of an email address string
 public static bool IsValidEmailAddress(this string s)
  {
   // I don't claim to understand the regex gibberish below
   Regex regex = new Regex(@"^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$");
   return regex.IsMatch(s);
  }
 }
}
&lt;/pre&gt;
Cool stuff:
The *this* keyword makes the static method attach itself to the type in the argument.
The summary for the method will appear in the autocompletion help.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-4513760781403263093?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/4513760781403263093/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2008/08/extension-methods-are-rad.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/4513760781403263093'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/4513760781403263093'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2008/08/extension-methods-are-rad.html' title='Extension methods are rad'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-7182583934554244387</id><published>2008-03-17T10:08:00.003-04:00</published><updated>2008-08-13T09:24:11.913-04:00</updated><title type='text'>The anti-comment</title><content type='html'>Does this comment make any sense to you whatsoever?

&lt;span style="FONT-STYLE: italic"&gt;Find the number of columns to be displayed. The column order of the last display column will tell us the number of columns that need to be displayed.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-7182583934554244387?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/7182583934554244387/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2008/03/anti-comment.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/7182583934554244387'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/7182583934554244387'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2008/03/anti-comment.html' title='The anti-comment'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-3444898188149721031</id><published>2008-02-07T11:31:00.000-05:00</published><updated>2008-02-07T11:33:25.270-05:00</updated><title type='text'>Training session eval</title><content type='html'>An instructor I had at a training session this week asked me for an evaluation, which was probably a mistake, because I'm kind of a Power Point anti-evangelist.  Here's what I told him:


&lt;span style="font-style: italic;"&gt;In exchange for the great pleasure of NOT having to fill in an evaluation form at the end of the training session, and toting home a certificate, I thought I should take a few minutes to write out a useful review of the presentation for you.&lt;/span&gt;

&lt;span style="font-style: italic;"&gt;I'm also going to make the assumption, since you're taking over the training duties, that Derek will not be reading this.  My criticism of his performance will not be kind, but in my experience, a professional presenter is his own worse critic.  So If he's offended by my remarks, then he might be the right man for the job.&lt;/span&gt;

&lt;span style="font-style: italic;"&gt;I'll split my critique into two parts.  First, I'll list those things that I think others in the class would agree with.  Then, I'll describe my own personal, and possibly caustic opinions on your training session, and most presentations in general.&lt;/span&gt;

&lt;span style="font-style: italic;"&gt;I'll also point out, right away, something you have no control over but is important nonetheless: We don't have this software where I work.  In fact, I didn't even really understand why I was going or what the course would really cover.  Therefore, my first criticism is to give a better overview of the topic area and Ounce's place in it.  Tell us the difference between application and system security and give us some examples.  SQL Injection is overused, and buffer overruns are not a problem in higher-level languages.  (Correct me if I'm wrong... I guess I'll soon find out.)  For an audience of developers, we need a better understanding of the problems your system will fix.  &lt;/span&gt;

&lt;span style="font-style: italic;"&gt;Using a virtual machine for a training environment is great.  Just be careful your facilitator has properly set it up.  Mine needed work.&lt;/span&gt;

&lt;span style="font-style: italic;"&gt;The exercises were great.  Loved using real code.&lt;/span&gt;

&lt;span style="font-style: italic;"&gt;Now, I'll get a bit more controversial, starting with my favorite app to hate: Powerpoint.  Powerpoint is killing the presentation for a few reasons:&lt;/span&gt;

&lt;span style="font-style: italic;"&gt;&lt;span style="font-weight: bold;"&gt;Slides are too wordy. &lt;/span&gt; Presenters write slides with whole paragraphs in them, and present us with dozens of slides I just quit reading.  I quit reading them because I have them on paper anyway, so why have a slide in the first place?&lt;/span&gt;

&lt;span style="font-style: italic;"&gt;&lt;span style="font-weight: bold;"&gt;Presenters read the slides. &lt;/span&gt; I think the reason slides are too wordy is the presenters just want to read what's on them.  Presenters don't work from outlines anymore, they just read the slides.  I think this is a waste of my time, because I could have read the slide myself.  Think back to all the lecturers you had in school, good or bad, and remember they would write their points on the board.  If they wrote it out, it was significant.  Now, with Powerpoint, where presenters cram every fact they can on a slide, it's impossible to separate the wheat from the chaff.&lt;/span&gt;

&lt;span style="font-style: italic;"&gt;&lt;span style="font-weight: bold;"&gt;Presenters print bulky books with the slides in them. &lt;/span&gt; The only reason I can detect to do this is to bring some kind of value-object the student can lug home.  But I have a computer in front of me, with which to read the slides if I want to, and a notebook with me, to take my notes in.  And you can put the slides on the disc you hand out.  Please replace the bulky slide/notebook with a thinner book that only a) contains the outline, if you want, and b) contains the exercises, so I can catch up when I fall behind.&lt;/span&gt;

&lt;span style="font-style: italic;"&gt;So, to sum up:&lt;/span&gt;
&lt;span style="font-style: italic;"&gt;Please give a good overview&lt;/span&gt;
&lt;span style="font-style: italic;"&gt;Virtual Machines are awesome&lt;/span&gt;
&lt;span style="font-style: italic;"&gt;Just say no to Powerpoint&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-3444898188149721031?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/3444898188149721031/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2008/02/training-session-eval.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/3444898188149721031'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/3444898188149721031'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2008/02/training-session-eval.html' title='Training session eval'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-7037180512853600356</id><published>2008-01-29T14:56:00.001-05:00</published><updated>2008-01-29T14:57:01.573-05:00</updated><title type='text'>Vim is rad</title><content type='html'>&lt;a href="http://reddit.com/r/programming/info/66wnd/comments/"&gt;Here &lt;/a&gt;is a great reddit comment about a cool Vim hack.  What I love about Vim is you can always find something interesting about it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-7037180512853600356?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/7037180512853600356/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2008/01/vim-is-rad.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/7037180512853600356'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/7037180512853600356'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2008/01/vim-is-rad.html' title='Vim is rad'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-891749153799388167</id><published>2008-01-17T09:58:00.000-05:00</published><updated>2008-01-17T10:00:10.379-05:00</updated><title type='text'>Good blog post on trees in database tables</title><content type='html'>I thought &lt;a href="http://www.rockstarapps.com/wordpress/?p=88"&gt;this &lt;/a&gt;was a pretty good approach to representing parent and tree-limb membership in a database.  I think I'll try it next time I have to build something like this.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-891749153799388167?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/891749153799388167/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2008/01/good-blog-post-on-trees-in-database.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/891749153799388167'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/891749153799388167'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2008/01/good-blog-post-on-trees-in-database.html' title='Good blog post on trees in database tables'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-8045966705311063548</id><published>2007-11-21T22:29:00.001-05:00</published><updated>2009-02-25T14:37:46.955-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Paranoia and Binary Formatters</title><content type='html'>So I'm chatting with the boss the other day.  He's trying to hire a senior developer.  As I fancy myself a senior developer, I ask him what kinds of questions he's asking his candidates.

"Oh, you know, the usual.  Like if they know how to do a deep copy in .NET.  Stuff like that."

This sends me into waves of panic.  I try to play it cool.  I'm like, "Yeah, sure.  Totally."  But inside, I'm thinking, "Wait a minute, &lt;span style="font-style: italic;"&gt;do I know&lt;/span&gt; how to do a deep or or shallow copy?  Am I really a senior developer?  Did I forget to wear pants today?" 

I did a little homework and this is what I found out.  First, I looked up the difference between deep and shallow copies on Wikipedia, which is the greatest web site in the world.  The difference between a shallow and deep copy is this: When you copy shallow, your new class contains references that point to all the same class instances the old one did.  When you do a deep copy, you get all new memory allocation for everything.

The advantage to the shallow is you are supposed to be optimizing for speed at the expense of data, because you're leaving out all that allocated RAM.  What people are finding out, so I read, is there's no serious tradeoff, so they tend to always make deep copies.  This jives with Raymond's Art of Unix Programming, which says you should hack the code first and optimize later.

So what's the best way to make a deep copy?

You'd think if the Creators of the Framework really wanted me do do More Work With Less Code, they would have some system library standing by.  But no.  Instead, I get ICloneable.  The Creators want to leave the implementation up to me.  OK, I can handle that.  So the first thing you do is implement the interface.

&lt;span style="font-family: verdana;"&gt;class Muppet : ICloneable&lt;/span&gt;

Now you have signed up to implement the Clone() method.  If you don't implement the method, you get a compiler error.

When you implement the clone method, you could create a new instance and assign all the properties to the values of the source of the copy.  Then you'd have to copy all the objects it contains references to.  And, I think, the real problem with this would be when you edit the object, you'd have to remember to add any new properties to the clone method.  A good unit test would spot that I suppose, but I guarantee you'd miss it more ofter than not.

So we use a binary serializer instead.  First, tag your class serializable.

&lt;span style="font-family: verdana;"&gt;[Serializable] &lt;/span&gt;
&lt;span style="font-family: verdana;"&gt;class Muppet : ICloneable&lt;/span&gt;

Then use a binary serializer to stuff a copy of your object into a memory stream and fetch the copy into a new instance:

&lt;pre&gt;
        public object Clone()
        {
            MemoryStream ms = new MemoryStream();
            BinaryFormatter bf = new BinaryFormatter();
            bf.Serialize(ms, this);
            ms.Position = 0;
            object newMuppet = bf.Deserialize(ms);
            ms.Close();
            return newMuppet;
        }

&lt;/pre&gt;
Sucks: you have to return an Object to implement the interface correctly.  So you ought to call the code like this:

Muppet fozzy = kermit.Clone() as Muppet;

... then test fozzy for null to be sure the copy came through.  Now you can add all the properties you want and you don't have to recode the Clone() method.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-8045966705311063548?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/8045966705311063548/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2007/11/paranoia-and-binary-formatters.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/8045966705311063548'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/8045966705311063548'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2007/11/paranoia-and-binary-formatters.html' title='Paranoia and Binary Formatters'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-1888945297006213299</id><published>2007-11-16T22:46:00.000-05:00</published><updated>2007-11-21T22:29:14.345-05:00</updated><title type='text'>Ubuntu is the greatest thing since sliced bread</title><content type='html'>I installed Ubuntu on a few machines around the house and I just have to say how impressed I am about it.

Tonight I thought I'd try to run gedit from the command prompt on this old Sony laptop.  I open the command window and type 'gedit'.  Rather than the editor, I get this:

&lt;span style="font-family:verdana;"&gt;gavin@sonny:~$ gedit&lt;/span&gt;
&lt;span style="font-family:verdana;"&gt;The program 'gedit' is currently not installed.  You can install it by typing:&lt;/span&gt;
&lt;span style="font-family:verdana;"&gt;sudo apt-get install gedit&lt;/span&gt;
&lt;span style="font-family:verdana;"&gt;bash: gedit: command not found&lt;/span&gt;

This is awesome on a couple of levels.  First, even thought the app is not installed, it is smart enough to tell me how to do it.  That is a great piece of software engineering.  Second, I type the command, and I've &lt;span style="font-weight: bold; font-style: italic;"&gt;learned something&lt;/span&gt;.

Ubuntu (XUbuntu to be fair) taught me how to use itself.  At the command line.

I am so impressed with this operating system.  What a thrill to use something that appears to be designed for computer users, not just tech gadget consumers.  This takes me back to the days of the Apple ][, when, if you didn't get it, you didn't deserve to own one.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-1888945297006213299?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/1888945297006213299/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2007/11/ubuntu-is-greatest-thing-since-sliced.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/1888945297006213299'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/1888945297006213299'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2007/11/ubuntu-is-greatest-thing-since-sliced.html' title='Ubuntu is the greatest thing since sliced bread'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-5937832172223443618</id><published>2007-11-01T21:33:00.000-04:00</published><updated>2007-11-01T22:07:08.069-04:00</updated><title type='text'>CSV vs. XML</title><content type='html'>Reading data from files can be fun and rewarding.  My favorite files have always been delimited ones.  Then I write a loop that looks something like this:

&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;            string[] data;&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;            List&lt;string[]&gt; lines = new List&lt;string[]&gt;();&lt;/string[]&gt;&lt;/string[]&gt;&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;            try&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;            {&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;    using (StreamReader sr = new StreamReader(filename))&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;                    {&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;        String line;&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;        while ((line = sr.ReadLine()) != null)&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;        {&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;            data = line.Split(',');&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;            lines.Add(data);&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;        }&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;    }&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;            }&lt;/span&gt;
&lt;/span&gt;
Granted, this is dangerous because the file might not be formatted correctly or may not have enough delimiters, but that's a problem we can handle easily.

Then came XML.

Most of the XML I deal with are files that we make from serialized objects using C#.  Then we read them into new instances later, all nice and tidy, no problems.   But I had to read in a file that had no DTD and no schema defined.  This was a bit of a pain because I had to turn off all the nice validation that happens behind the scene.  And then I have to wrap my head around the whole event-driven model thing.  I don't want my text file telling me when it's time to read its lines.  I should be telling it what to do.

Anyways, here's what I hacked together to read in the XML:
&lt;span style="font-size:85%;"&gt;
&lt;span style="font-family:courier new;"&gt;        // these are the tags we're looking for
       private const string CONTEXTENTRY = "contextentry";
       private const string ATTRIBUTE_ID = "id";
       private const string ATTRIBUTE_PAGE = "page";

       public PPF_File(string path)&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;        {&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;            ContextEntries = new List&lt;contextentry&gt;();&lt;/contextentry&gt;&lt;/span&gt;

&lt;span style="font-family:courier new;"&gt;            // need to turn off the DTD requirement; won't work without this.&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;            XmlReaderSettings settings = new XmlReaderSettings();&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;            settings.ProhibitDtd = false;&lt;/span&gt;

&lt;span style="font-family:courier new;"&gt;            // opens the file&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;            XmlReader xmlReader = XmlReader.Create(path,settings);&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;            &lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;            // build out collection&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;            while (xmlReader.Read())&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;            {&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;                if (xmlReader.Name == CONTEXTENTRY)&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;                {&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;                    if (xmlReader.HasAttributes)&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;                    {&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;                        ContextEntries.Add(new ContextEntry(xmlReader.GetAttribute(ATTRIBUTE_ID), xmlReader.GetAttribute(ATTRIBUTE_PAGE)));&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;                    }&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;                }&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;            }&lt;/span&gt;

&lt;span style="font-family:courier new;"&gt;            // bye bye file&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;            xmlReader.Close();&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;        }&lt;/span&gt;&lt;/span&gt;

This worked pretty well.  ContextEntries is a List&lt;&gt; made up of a class I put together to hold the values in the node.  The constuctor sets the properties for me.

Maybe if I dealt more with the aspect of programming with XML where the benefits of the event-driven XML model were more apparent, or where they were completely hidden to me I might appreciate XML more.  But it seems like a lot more work (and memory usage, from what I've read) to do something we could have either done more cheaply with a simpler file or more effectively with some kind of binary file.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-5937832172223443618?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/5937832172223443618/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2007/11/reading-data-from-files-can-be-fun-and.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/5937832172223443618'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/5937832172223443618'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2007/11/reading-data-from-files-can-be-fun-and.html' title='CSV vs. XML'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-6461866105502709137</id><published>2007-09-14T08:04:00.000-04:00</published><updated>2007-09-14T08:16:33.109-04:00</updated><title type='text'>Internet Connection</title><content type='html'>I had come to rely on the Internet connection at my office to post programming tidbits to this blog.  As I learned something interesting, I would start composing the post and post it when I was done.

But for the last few months, I haven't had an Internet connection at the office!  My productivity improved (slightly... I suffer more from incomplete specifications then I do from Internet distractions) but my connection to the outside world disappeared. 

I have two small children at home, ages 1 and 4, so I try to spend as much time with them as I can when I'm at home.  And I leave for work before 6:00 AM, so I don't give myself much time to play around with code after they go to bed.  (Believe it or not, but when I have to choose between drinking a glass of wine with my wife and playing around with code, I choose the wife.  Got to keep the wife happy!)

Anyways, I've been messing with Linux and Python lately, so I am planning on posting some new stuff shortly.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-6461866105502709137?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/6461866105502709137/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2007/09/internet-connection.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/6461866105502709137'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/6461866105502709137'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2007/09/internet-connection.html' title='Internet Connection'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-9069844014188394218</id><published>2007-05-08T15:44:00.001-04:00</published><updated>2008-11-17T12:02:59.101-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='computers'/><title type='text'>Win XP Virtual Control Panel is rad</title><content type='html'>Microsoft development software, databases and operating systems have been the cornerstone of my career for fifteen years.  For that reason, I despise Microsoft naming conventions and upgrade paths.  The first challenge is trying to figure out just what software I need to download and learn.  Do I need Silverlight?  Express?  Orcas?  The .NET framework 3.0?  3.5?  (Where did THAT come from?)

In the end, I decided to download Orcas beta 1 professional edition.  I made the decision because I know from past experience the studio usually includes all the parts I want to study.

I downloaded the five-gigabyte DVD ISO image from the MSDN website.  That took a while a probably incremented the secret bit counter on my Comcast meter, but you gotta do what you gotta do.

Let me say a few words about ISO images.  I hate CD and DVD burners.  Maybe its just me, but the failure rate on these things is too high.  I own three computers with burners on them.  One of them throws errors whenever I try to make an optical disk.  The error says "insufficient voltage", so I'm guessing there are too many other things in the machine drawing power, which is irritating because it uses a 350-watt power supply!  (I built it myself to drive an expensive video card and two hard disks.)  I suppose I could disconnect one of the disks, or downgrade the video card, but geez!  What a pain!

So there's my Thinkpad, but it does not appear to have a program that will burn CD images from ISO files.  It won't play DVD films either, but that's not mission-critical.

Then there's my old development box, which had a CD burner on it and ALSO does not have any software to make an image from an ISO file.  I really don't want to spend any money for this feature.  But there's an alternative.

When I download an ISO, is use a program I found online called &lt;a href="http://download.microsoft.com/download/7/b/6/7b6abd84-7841-4978-96f5-bd58df02efa2/winxpvirtualcdcontrolpanel_21.exe"&gt;winxpvirtualcdcontrolpanel&lt;/a&gt;.  You can find it on the Microsoft website.  It's a free, but unsupported tool for people like me who download a lot of ISO files.

I download the files, then copy them to my portable drive.  I can mount the file as a drive, and voila, I've avoided using a laser beam completely.  Also works with DVD ISO files.

I'd also like to point out that if you move the ISO file, the mounted drive moves with it.  That's a pretty significant feature and I'd like to give an invisible high-five to the developer for that.

I also appreciate that I can mount an ISO file as a drive to a virtual machine in Microsoft's virtual PC.  Also quite handy for reinstalling operating systems.

So now: I've got the "DVD" mounted and I'm reading the quite-intimidating uninstallation instructions.  I hope I don't regret this.  I should probably uninstall VS 2005 first...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-9069844014188394218?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/9069844014188394218/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2007/05/win-xp-virtual-control-panel-is-rad.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/9069844014188394218'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/9069844014188394218'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2007/05/win-xp-virtual-control-panel-is-rad.html' title='Win XP Virtual Control Panel is rad'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-494112260012691407</id><published>2007-05-04T08:26:00.000-04:00</published><updated>2007-05-04T08:28:32.292-04:00</updated><title type='text'>Windows Indexing Service and SQL Server 2005</title><content type='html'>I had an interesting assignment this week involving databases and documents. 

Our group supports an in-house product that provides workflow management services for it's users.  The workflow items have document attachments.  So, naturally, this leads to some perfectly reasonable requests like "Find me every instance of a workflow item that is open, assigned to Bob, and has a document attachment with the words "godfather of soul" in it.

The first two criteria of the problem you would imagine are simple parts of a where clause of a SQL statement.  But that last part is the tricky one.  Our schema contains a "pointer" table that contains the path and filename of the document, but not the contents of the document itself.  So there's no way to include a where clause for that.  Or so I thought. 

I knew from my IIS training when I was working on my (now mostly useless) MCSE certification for NT 4.0 that the IIS system could be easily integrated with an indexing service for searching for documents.   I also knew from searching for documents on my C: drive (with the yellow dog, how friendly) there was a local indexing service built into the operating system. 

Although we already have a system for doing this through a third-party vendor, we have to pay them licensing fees for functionality that we already have. 

We already have this functionality in our system.  We pay an annual license fee for a third-party indexing system.  The indexing system, in order to combine the results of the document indexing with the database indexing, opens database connections and reads in our workflow records in great quantities.  SQL server is designed to lock the entire contents of a table when a row is being read, so this has the potential to lock out the users of the system. 

Creating table (non-clustered) indexes is one of the basic features of SQL Server.  There had to be a way, I thought, to combine the indexing power of SQL Server and the document indexing service built into the Windows OS.  As it turns out, there is a way.  And it doesn't open database connections.  And it costs $0.00 extra.

One of the features of SQL Server, you probably know if you're a SQL Server hacker, is it can process queries that span server instances.  In other words, it was designed to let you keep data on several different servers and gather your query results from all of them at the same time.

Here's something I learned this week: they other linked servers in the group don't have to be SQL Server databases.  They can be anything that has had an OLE DB driver written for it, which is quite a lot of things.  One of them is the indexing service. 

(I'm no expert on low-level driver code, but I know that OLE DB is still the underlying method for passing data around Windows machines.  When you use an ODBC driver, for example, it's sending your queries through the OLE DB driver.

The OLE DB driver for the Microsoft Indexing Service is called MSIDXS.  In order to set this up, we have to perform a few steps:

&lt;ol&gt;&lt;li&gt;Find a bunch of stuff to index.&lt;/li&gt;&lt;li&gt;Make sure your Windows box has the DLL's it needs to open the files.&lt;/li&gt;&lt;li&gt;Make a catalog&lt;/li&gt;&lt;li&gt;Index the stuff&lt;/li&gt;&lt;li&gt;Link the indexing service catalog to the SQL Server&lt;/li&gt;&lt;li&gt;Write a query that returns results from the Indexing Service, through the SQL Server, to your query window.&lt;/li&gt;&lt;/ol&gt;
&lt;span style="font-weight: bold;"&gt;Find a bunch of stuff to index&lt;/span&gt;
This might be the toughest part.  I was lucky because I was working on an existing project that already had the documents and the table I needed.  But if you don't, make this:

1. A directory of documents.  Don't limit yourself to Word docs.  Use Excel sheets, PDF files, text files, images and MP3's.  The images and music files have their meta-data to offer to the indexing service. 

2. A table in the database with the path and filename of the document in question.  In my case, all six-thousand of my documents had unique names because the service that saved them there changed their names by prepending the record number to it. 

&lt;span style="font-weight: bold;"&gt;Make sure your Windows box has the DLL's&lt;/span&gt;
As you can imagine, the service has to open each file, read the contents, and store the index based on those contents.  Text files and Word documents are easy, because the Windows OS already has what it needs to open those files.  (WordPad is used to open .doc files.)  But if you want to index PDF files, you have to install the Acrobat Reader on the machine.

&lt;span style="font-weight: bold;"&gt;Make a Catalog&lt;/span&gt;
All you have to do to make a catalog is open the Indexing Service.  Here's my favorite way to do it:

&lt;ol&gt;&lt;li&gt;Start, run, "MMC"&lt;/li&gt;&lt;li&gt;File, Add Snap-in&lt;/li&gt;&lt;li&gt;Add... Indexing Service&lt;/li&gt;&lt;li&gt;Local computer (More to be said on this topic.)&lt;/li&gt;&lt;/ol&gt;
Right-click on the Indexing Service root and add a catalog.  Specify the directory where the catalog will be saved.  Remember: you're making the catalog itself, not specifying the directory that will be indexed.

&lt;span style="font-weight: bold;"&gt;Index the Stuff&lt;/span&gt;
Start your indexing service and wait.  I indexed six thousand documents in less than an hour, but it took several hours to do the same thing when I added a shared directory from a file server.  Think about this: when the indexing service is indexing files locally, they take a lot less time then when you do it from a remote machine.  That makes a lot of sense to me, because it has to open each file to read the contents and build the index.  If the file open operation has to take place over a network, that's a lot more overhead.

&lt;span style="font-weight: bold;"&gt;Link the indexing service to the SQL Server&lt;/span&gt;
You have to register the Index Server with the SQL Server using the stored procedure "sp_AddLinkedServer"  This will enable it to be accessed through the OpenQuery method.  Use the command:
&lt;span style="font-family: courier new;"&gt;exec sp_addlinkedserver &lt;servername&gt;, &lt;ole&gt;, &lt;providername&gt;, &lt;datasource&gt;&lt;/span&gt;

I used this statment:
&lt;span style="font-family: courier new;"&gt;exec sp_addlinkedserver DocumentCatalog, 'IndexServer', 'MSIDXS', 'DocumentCatalog'&lt;/span&gt;

DocumentCatalog is the name of the catalog I made in the Index Server.  I'm not sure which of the two reference to the name is the actual catalog and which one makes the OPENQUERY statement work.  Although I ran it successfully, the optional parameters for this system procedure are a little overwhelming.  Check the Books Online for more information.

&lt;span style="font-weight: bold;"&gt;Write the query&lt;/span&gt;
The goal with this step is to design a query that can pull information from BOTH the database tables AND the index.  The OPENQUERY statement is what SQL Server uses to connect to a linked server through OLE DB.

The actual query statement:
&lt;span style="font-family: courier new;"&gt;select * from document_metadata_table m&lt;/span&gt;
&lt;span style="font-family: courier new;"&gt;join&lt;/span&gt;
&lt;span style="font-family: courier new;"&gt;    (select * from OPENQUERY &lt;/span&gt;
&lt;span style="font-family: courier new;"&gt;        (DocumentCatalog, 'select filename from SCOPE() where CONTAINS('godfather of soul')&lt;/span&gt;
&lt;span style="font-family: courier new;"&gt;    ) a&lt;/span&gt;
&lt;span style="font-family: courier new;"&gt;on a.Filename = m.filename&lt;/span&gt;
&lt;span style="font-family: courier new;"&gt;join workflow w on m.w_id = w.w_id&lt;/span&gt;
&lt;span style="font-family: courier new;"&gt;where w.assigned_to = 'bob' and status = 'open'&lt;/span&gt;

A few tips:

The Indexing Service SDK contains a reference to the Indexing service query language.  That's where I got the CONTAINS statement. 

When you add the Indexing Service to the MMC as a snap-in, open the help from there for more information about the nuts and bolts of the indexing service itself.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-494112260012691407?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/494112260012691407/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2007/05/windows-indexing-service-and-sql-server.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/494112260012691407'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/494112260012691407'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2007/05/windows-indexing-service-and-sql-server.html' title='Windows Indexing Service and SQL Server 2005'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-8139804114132445244</id><published>2007-04-11T12:39:00.000-04:00</published><updated>2007-04-11T14:28:03.088-04:00</updated><title type='text'>C#, the REF keyword, the heap and the stack</title><content type='html'>&lt;span style="font-size:100%;"&gt;&lt;span style="font-family: times new roman;"&gt;As a developer, its really really good to know what you're actually passing around to functions.  When I hand a variable of some type to a function, what is going to happen to it?  Today. I had a colleague ask me what would come back from the function parameter he was passing a class instance to.  I wasn't 100% sure on the answer, so I did a little digging.&lt;/span&gt;

&lt;span style="font-family: times new roman;"&gt;This is one of those programming problems I enjoy because the answer lies in understanding the difference between the stack and the heap, and the difference between value and reference types in C#.&lt;/span&gt;

&lt;span style="font-family: times new roman;"&gt;When you create a value type, you're allocating memory on the stack, in the same place where the function itself is placed.  For that reason, when you pass the value type to the next function in one of its parameters, you're getting a new allocation on a new spot on the stack; hence, a copy of the variable.&lt;/span&gt;

&lt;span style="font-size:78%;"&gt;&lt;span style="font-family: courier new;"&gt;int i = 1;&lt;/span&gt;
&lt;span style="font-family: courier new;"&gt;Console.WriteLine("TestFunctions creates i = " + i.ToString());&lt;/span&gt;
&lt;span style="font-family: courier new;"&gt;CopyValueIncrement(i);&lt;/span&gt;
&lt;span style="font-family: courier new;"&gt;Console.WriteLine("TestFunctions return from CopyValueIncrement i.ToString() = " + i.ToString());&lt;/span&gt;

&lt;span style="font-family: courier new;"&gt;private void CopyValueIncrement(int i)&lt;/span&gt;
&lt;span style="font-family: courier new;"&gt;   {&lt;/span&gt;
&lt;span style="font-family: courier new;"&gt;       i++;&lt;/span&gt;
&lt;span style="font-family: courier new;"&gt;       Console.WriteLine("CopyValueIncrement i = " + i.ToString());&lt;/span&gt;
&lt;span style="font-family: courier new;"&gt;   }&lt;/span&gt;

&lt;span style="font-family: courier new;"&gt;TestFunctions creates i = 1&lt;/span&gt;
&lt;span style="font-family: courier new;"&gt;CopyValueIncrement i = 2&lt;/span&gt;
&lt;span style="font-family: courier new;"&gt;TestFunctions return from CopyValueIncrement i.ToString() = 1&lt;/span&gt;&lt;/span&gt;

&lt;span style="font-family: times new roman;"&gt;When you use the "ref" keyword to declare and use the parameter with your value type, the compiler will go to the trouble of passing some kind of reference (a pointer, I suppose) to the value type in the calling function.&lt;/span&gt;
&lt;/span&gt;&lt;span style="font-family: times new roman;font-size:100%;" &gt;
&lt;/span&gt;&lt;span style="font-family: times new roman;font-size:100%;" &gt;&lt;span style="font-size:78%;"&gt;
&lt;span style="font-family: courier new;"&gt;        int i = 1;&lt;/span&gt;
&lt;span style="font-family: courier new;"&gt;        Console.WriteLine("TestFunctions creates i = " + i.ToString());&lt;/span&gt;
&lt;span style="font-family: courier new;"&gt;        RefValueIncrement(ref i);&lt;/span&gt;
&lt;span style="font-family: courier new;"&gt;        Console.WriteLine("TestFunctions return from RefValueIncrement i.ToString() = " + i.ToString());&lt;/span&gt;

&lt;span style="font-family: courier new;"&gt;        private void RefValueIncrement(ref int i)&lt;/span&gt;
&lt;span style="font-family: courier new;"&gt;        {&lt;/span&gt;
&lt;span style="font-family: courier new;"&gt;            i++;&lt;/span&gt;
&lt;span style="font-family: courier new;"&gt;            Console.WriteLine("RefValueIncrement i = " + i.ToString());&lt;/span&gt;
&lt;span style="font-family: courier new;"&gt;        }&lt;/span&gt;
&lt;/span&gt;
Will return:
&lt;/span&gt;&lt;span style="font-family: times new roman;font-size:100%;" &gt;&lt;span style="font-size:78%;"&gt;&lt;span style="font-family: courier new;"&gt;TestFunctions creates i = 1&lt;/span&gt;
&lt;span style="font-family: courier new;"&gt; RefValueIncrement i = 2&lt;/span&gt;
&lt;span style="font-family: courier new;"&gt; TestFunctions return from RefValueIncrement i.ToString() = 2&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;span style="font-size:100%;"&gt;
&lt;/span&gt;&lt;span style="font-family: times new roman;font-size:100%;" &gt;Now, the funny part is when you move to class instances, or reference types.  These are allocated on the heap, and what you get on the stack is the pointer to it.  So it doesn't matter if you pass it normally or by reference, the function you pass it to still affects the single class instance; there is no copy.  Observe: the return from both versions of this code is the same effect.
&lt;span style="font-size:78%;"&gt;
&lt;span style="font-family: courier new;"&gt;            testclass t = new testclass();&lt;/span&gt;
&lt;span style="font-family: courier new;"&gt;            t.Score = 55;&lt;/span&gt;
&lt;span style="font-family: courier new;"&gt;            Console.WriteLine("TestFunctions creates instance of testclass, .Score = " + t.Score.ToString());&lt;/span&gt;

&lt;span style="font-family: courier new;"&gt;            ClassRefFunc(ref t);&lt;/span&gt;
&lt;span style="font-family: courier new;"&gt;            Console.WriteLine("TestFunctions return from ClassRefFunc t.Score.ToString() = " + t.Score.ToString());&lt;/span&gt;

&lt;span style="font-family: courier new;"&gt;            ClassValueFunc(t);&lt;/span&gt;
&lt;span style="font-family: courier new;"&gt;            Console.WriteLine("TestFunctions return from ClassValueFunc t.Score.ToString() = " + t.Score.ToString());&lt;/span&gt;

&lt;span style="font-family: courier new;"&gt;        private void ClassRefFunc(ref testclass t)&lt;/span&gt;
&lt;span style="font-family: courier new;"&gt;        {&lt;/span&gt;
&lt;span style="font-family: courier new;"&gt;            t.Score = 99;&lt;/span&gt;
&lt;span style="font-family: courier new;"&gt;            Console.WriteLine("ClassRefFunc t.Score = " + t.Score.ToString());&lt;/span&gt;
&lt;span style="font-family: courier new;"&gt;        }&lt;/span&gt;

&lt;span style="font-family: courier new;"&gt;        private void ClassValueFunc(testclass t)&lt;/span&gt;
&lt;span style="font-family: courier new;"&gt;        {&lt;/span&gt;
&lt;span style="font-family: courier new;"&gt;            t.Score = 88;&lt;/span&gt;
&lt;span style="font-family: courier new;"&gt;            Console.WriteLine("ClassValueFunc t.Score = " + t.Score.ToString());&lt;/span&gt;
&lt;span style="font-family: courier new;"&gt;        }&lt;/span&gt;


&lt;span style="font-family: courier new;"&gt;TestFunctions creates instance of testclass, .Score = 55&lt;/span&gt;
&lt;span style="font-family: courier new;"&gt;ClassRefFunc t.Score = 99&lt;/span&gt;
&lt;span style="font-family: courier new;"&gt;TestFunctions return from ClassRefFunc t.Score.ToString() = 99&lt;/span&gt;
&lt;span style="font-family: courier new;"&gt;ClassValueFunc t.Score = 88&lt;/span&gt;
&lt;span style="font-family: courier new;"&gt;TestFunctions return from ClassValueFunc t.Score.ToString() = 88&lt;/span&gt;&lt;/span&gt;

So the long and the short of it is, class instances are always passed by reference because you're &lt;span style="font-style: italic;"&gt;passing a copy of the pointer&lt;/span&gt;... unless you use the "ref" keyword, in which case you're passing a reference to the pointer... &lt;span style="font-style: italic;"&gt;to the same class instance&lt;/span&gt;.  The effect is the same.
&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-8139804114132445244?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/8139804114132445244/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2007/04/c-ref-keyword-heap-and-stack.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/8139804114132445244'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/8139804114132445244'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2007/04/c-ref-keyword-heap-and-stack.html' title='C#, the REF keyword, the heap and the stack'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-365336919526343423</id><published>2007-04-09T15:46:00.000-04:00</published><updated>2007-04-09T15:52:24.372-04:00</updated><title type='text'>Vim default fonts</title><content type='html'>I use GVim as my default text editor.  I enjoy this editor because its got many features, most of which I don't use, and I appreciate the keyboard-centric nature of it.  The price is right, and it keeps me in practice for those inevitable times I have to make edits to a configuration file on  *nix server over a terminal session.

I hate the fact that the default font is System on Windows.  The System font is hideous.  I finally found out how to change the default font:

&lt;ol&gt;&lt;li&gt;Open the editor.&lt;/li&gt;&lt;li&gt;Set the font to your favorite.&lt;/li&gt;&lt;li&gt;Press : to enter a text command.&lt;/li&gt;&lt;li&gt;:set guifont=&lt;/li&gt;&lt;li&gt;&lt;tab&gt;When you press tab, the current font string key will fill in.  Copy it into the clipboard buffer.&lt;/tab&gt;&lt;/li&gt;&lt;li&gt;&lt;tab&gt;Edit _vimrc, located in the Vim program directory.&lt;/tab&gt;&lt;/li&gt;&lt;li&gt;&lt;tab&gt;Paste the command somewhere in there.  I made it the fifth or sixth line.  Save that thing.&lt;/tab&gt;&lt;/li&gt;&lt;/ol&gt;&lt;tab&gt;
From this day forward, you will get your default font when you edit a file.&lt;/tab&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-365336919526343423?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/365336919526343423/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2007/04/vim-default-fonts.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/365336919526343423'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/365336919526343423'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2007/04/vim-default-fonts.html' title='Vim default fonts'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-7313780165618207689</id><published>2007-04-05T09:17:00.000-04:00</published><updated>2007-04-05T09:36:13.847-04:00</updated><title type='text'>When do I construct a struct?</title><content type='html'>Having been a C# hacker for some time, I'm used to throwing together classes as part of my solutions to problems.  But when you read the C# manuals, they don't start with classes.  The manuals start with structs.

I never write structs.  Why should I write something that looks like a class but doesn't have the advantage of inheritance?  Well, I finally found out the answer.

Since structs are value types and not reference types, their memory is allocated on the stack and not the heap.  So they behave a little differently.

When you pass them to functions, the called function gets a &lt;span style="font-style: italic;"&gt;copy of the struct&lt;/span&gt;.  So changes you make to the value-type struct in the called function are not seen by the caller.  When the instance size is less than 16 bytes, this is more efficient.

When you pass a class instance to a function, you get a &lt;span style="font-style: italic;"&gt;copy of the pointer to the instance&lt;/span&gt;, so your operations on the instance of the class on the heap are seen by the calling function.

The documentation also sites these reasons for using a struct over a class instance:
&lt;ul&gt;&lt;li&gt;Logically represents a single value&lt;/li&gt;&lt;li&gt;Has instance size of less than 16 bytes&lt;/li&gt;&lt;li&gt;Will not be changed after creation&lt;/li&gt;&lt;li&gt;Will not be cast to a reference type&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/8772123162990273002-7313780165618207689?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/7313780165618207689/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2007/04/when-do-i-construct-struct.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/7313780165618207689'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/7313780165618207689'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2007/04/when-do-i-construct-struct.html' title='When do I construct a struct?'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-1601908840826628951</id><published>2007-04-02T15:38:00.000-04:00</published><updated>2007-04-02T15:49:09.353-04:00</updated><title type='text'>Crystal Reports XI and .NET 2.0</title><content type='html'>I have a set of twenty or so reports I run every Friday.  I have been doing this manually for months because I never had the time to automate the process.  Today I had some down time so I set out to write a simple console C# app that would push the reports out.

The problem with Crystal was there was no API documentation.  I went to the web site and could not find anything to view or download.  The documentation map said the API documentation was installed into the Visual Studio documentation if VS and CR XI are installed on the same machine.  This did not prove to be true on either one of my machines.

I was able to find the examples, though, and there was one in particular that showed me what I needed.  The reports used ODBC connections to fetch their data from SQL Server stored procedures.  I simply wrote something like this;

&lt;span style="font-style: italic;"&gt;using CrystalDecisions.CrystalReports.Engine;&lt;/span&gt;
&lt;span style="font-style: italic;"&gt;using CrystalDecisions.Shared;&lt;/span&gt;

You have to include both libraries so you get the constants.

&lt;span style="font-style: italic;"&gt;ReportDocument rd = new ReportDocument();&lt;/span&gt;
&lt;span style="font-style: italic;"&gt;rd.Load("rpt_file_path");&lt;/span&gt;

&lt;span style="font-style: italic;"&gt;rd.SetParameterValue("@StartDate", DateTime.Parse(StartDate));&lt;/span&gt;
&lt;span style="font-style: italic;"&gt;rd.SetParameterValue("@EndDate", DateTime.Parse(EndDate));&lt;/span&gt;

These are parameters in the report, which are reflections of the parameters in the source stored procedure.  You have to know what the parameters are going to be to code it this way, but that's OK because this is a utility just for me.

&lt;span style="font-style: italic;"&gt;rd.ExportToDisk(ExportFormatType.PortableDocFormat, "c:\\my_dir\\rpt.pdf");&lt;/span&gt;

This is a pretty powerful line of code because it will connect to the database, execute the report, and send it to a PDF file, without the need to add a PDF library reference to my project.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-1601908840826628951?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/1601908840826628951/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2007/04/crystal-reports-xi-and-net-20.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/1601908840826628951'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/1601908840826628951'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2007/04/crystal-reports-xi-and-net-20.html' title='Crystal Reports XI and .NET 2.0'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8772123162990273002.post-7840432423718202661</id><published>2007-03-30T11:08:00.000-04:00</published><updated>2007-04-03T07:29:30.397-04:00</updated><title type='text'>SQL Server 2000 autogenerates DDL</title><content type='html'>Today I learned SQL Server 2000 will allow you to make a quick, backup copy of the schema of a table, even if it has an IDENTITY integer key, and copy all the data rows from the source table to the destination in one easy line of SQL:

&lt;span style="font-family:courier new;"&gt;select * into &lt;/span&gt;&lt;span style="font-style: italic;font-family:courier new;" &gt;destination_table&lt;/span&gt;&lt;span style="font-family:courier new;"&gt; from &lt;/span&gt;&lt;span style="font-style: italic;font-family:courier new;" &gt;source_table&lt;/span&gt;

I assume it would also do this if I made a table variable in a stored procedure.

This is much easier than asking Query Analyzer to generate a CREATE TABLE statement for my table, then hacking all the constraint names and removing the identity manually.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8772123162990273002-7840432423718202661?l=invalidobject.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://invalidobject.blogspot.com/feeds/7840432423718202661/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://invalidobject.blogspot.com/2007/03/today-i-learned-sql-server-2000-will.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/7840432423718202661'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8772123162990273002/posts/default/7840432423718202661'/><link rel='alternate' type='text/html' href='http://invalidobject.blogspot.com/2007/03/today-i-learned-sql-server-2000-will.html' title='SQL Server 2000 autogenerates DDL'/><author><name>Gavin</name><uri>http://www.blogger.com/profile/04776139608075049236</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://2.bp.blogspot.com/_cuJk5OBwokQ/SoE9NXoFEPI/AAAAAAAAAQA/vOOwmgu_Ups/S220/contrarian_trollcat.jpg'/></author><thr:total>1</thr:total></entry></feed>
