<?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-13073408</id><updated>2011-12-28T12:07:50.458-05:00</updated><category term='c#'/><category term='LINQ'/><category term='Visual Studio'/><category term='technology'/><category term='csharp'/><category term='MVC'/><category term='bugs'/><category term='development'/><category term='programming'/><category term='Razor'/><category term='web development'/><category term='productivity'/><category term='Windows7'/><category term='Windows'/><category term='IIS'/><category term='networking'/><category term='hardware'/><category term='database'/><category term='.NET'/><category term='ASP.NET'/><category term='T4MVC'/><title type='text'>Compiled Thoughts</title><subtitle type='html'>Here you'll find compiled thoughts on software development, technology and occasionally general life matters from me, Peter Lanoie.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>85</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-13073408.post-9045566677603293960</id><published>2011-11-21T16:59:00.000-05:00</published><updated>2011-11-21T16:59:12.983-05:00</updated><title type='text'>I donated and so should you.</title><content type='html'>I read Wikipedia at least once a day. &amp;nbsp;Usually many times a day. &amp;nbsp;So...&lt;br /&gt;&lt;br /&gt;&lt;a href="https://wikimediafoundation.org/wiki/Support_Wikipedia/en"&gt;&lt;img alt="Support Wikipedia" border="0" src="//upload.wikimedia.org/wikipedia/commons/2/26/Fundraising_2009-square-thanks-en.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;You have taught me so much that I was curious about and so much about what I didn't know I wanted to know.  Keep up the good work.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-9045566677603293960?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/9045566677603293960/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=9045566677603293960' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/9045566677603293960'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/9045566677603293960'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2011/11/i-donated-and-so-should-you.html' title='I donated and so should you.'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-2714049410204791420</id><published>2011-11-07T10:52:00.000-05:00</published><updated>2011-11-07T10:52:57.799-05:00</updated><title type='text'>My professional philosophy: "The General Problem" from xkcd</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;I don't think anything could describe my professional philosophy more succinctly or clearly than &lt;a href="http://xkcd.com/974/"&gt;this xkcd comic&lt;/a&gt;:&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;"&lt;b&gt;The General Problem&lt;/b&gt;"&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://xkcd.com/974/" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="133" src="http://imgs.xkcd.com/comics/the_general_problem.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;blockquote class="tr_bq"&gt;"I find that when someone's taking time to do something right in the present, they're a perfectionist with no ability to prioritize, whereas when someone took time to do something right in the past, they're a master artisan of great foresight."&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-2714049410204791420?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/2714049410204791420/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=2714049410204791420' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/2714049410204791420'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/2714049410204791420'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2011/11/my-professional-philosophy-general.html' title='My professional philosophy: &quot;The General Problem&quot; from xkcd'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-9133927829133089140</id><published>2011-07-13T15:39:00.002-04:00</published><updated>2011-07-13T15:45:17.694-04:00</updated><title type='text'>It's not easy being green</title><content type='html'>I had once been directly involved with the development team for an automotive market software product. &amp;nbsp;As a result, I worked with resources from the Automotive Aftermarket Industry Association and ended up on their mailing list for their publication: "Aftermarket Insider" which I receive monthly. &amp;nbsp;Volume 70 arrived recently. &amp;nbsp;I noticed, as often happens with periodical advertising supplements, that the issue was wrapped in a plastic sleeve containing a loose insert along with the primary publication. &amp;nbsp;I thought nothing of it until I noticed the content of the insert. &amp;nbsp;It was very nice, recycled card stock with a printed gloat about how "The automotive aftermarket industry was green long before being green was mainstream." &lt;br /&gt;&lt;br /&gt;Really? &amp;nbsp;You tell me this by including it on&amp;nbsp;unnecessarily&amp;nbsp;thick paper enshrouded in plastic?&lt;br /&gt;&lt;br /&gt;Instead,&amp;nbsp;you could have emailed that to me&amp;nbsp;in one of your regular blast mails from which I still can't seem to unsubscribe...&lt;br /&gt;&lt;br /&gt;*sigh*&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-VqDMrGCghmA/Th30NnMfojI/AAAAAAAABP8/poBYPxawN1o/s1600/0713011523.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="480" src="http://1.bp.blogspot.com/-VqDMrGCghmA/Th30NnMfojI/AAAAAAAABP8/poBYPxawN1o/s640/0713011523.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-9133927829133089140?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/9133927829133089140/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=9133927829133089140' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/9133927829133089140'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/9133927829133089140'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2011/07/its-not-easy-being-green.html' title='It&apos;s not easy being green'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-VqDMrGCghmA/Th30NnMfojI/AAAAAAAABP8/poBYPxawN1o/s72-c/0713011523.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-2579961017589649445</id><published>2011-06-13T11:23:00.001-04:00</published><updated>2011-06-13T11:25:39.083-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='productivity'/><category scheme='http://www.blogger.com/atom/ns#' term='technology'/><category scheme='http://www.blogger.com/atom/ns#' term='development'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>1 Year = 2.6 Million Keystrokes</title><content type='html'>&lt;span class="Apple-style-span" style="font-size: large;"&gt;A look back at my last year of typing.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Having mild OCD is advantageous to being a programmer. &amp;nbsp;But it has its drawback, such as forgetting to take breaks, use the bathroom, eat and sleep. &amp;nbsp;In April 2010, after&amp;nbsp;seeing a coworker using it, I installed &lt;a href="http://www.workrave.org/"&gt;Workrave&lt;/a&gt;&amp;nbsp;on my work desktop to help my effort&amp;nbsp;to be better about taking breaks. &amp;nbsp;Workrave is a task tray tool that pops up reminders to take micro-breaks (to stretch your various&amp;nbsp;appendages and eyes), longer breaks and can alert you to help limit your overall daily computer use, in whichever combinations you so choose. &amp;nbsp;All of this is an effort to help reduce&amp;nbsp;repetitive&amp;nbsp;stress injuries common among heavy computer users. &amp;nbsp;Along with these features, Workrave tracks your&amp;nbsp;key-presses&amp;nbsp;and mouse movement distance. &amp;nbsp;Since my "mouse" is a trackball and thus never really moves, the mouse movement figures are generally useless. &amp;nbsp;(However, it does track movement time which could be helpful for tracking how long your hand is working the mouse.) &amp;nbsp;The keystroke count is much more concrete, which gave me an idea.&lt;br /&gt;&lt;br /&gt;I started recording the daily keystroke stats and now have some impressive numbers. &amp;nbsp;Since April 9th 2010,&amp;nbsp;2,899,821 keystrokes have been recorded. &amp;nbsp;Excluding those after April 9th of this year, the total is&amp;nbsp;2,599,992. &amp;nbsp;That's 2.6 Million keystrokes for one calendar year. &lt;br /&gt;&lt;br /&gt;I moved the stats from post 4/9/2011 to the beginning to create one complete calendar year, and came up with the following&amp;nbsp;detailed figures:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Grand Total: 2,599,992&lt;/li&gt;&lt;li&gt;Monthly Average: 216,666&lt;/li&gt;&lt;li&gt;Highest Month: 291,506 (Feb)&lt;/li&gt;&lt;li&gt;Daily Average: 11,255&lt;/li&gt;&lt;li&gt;Highest Day: 29,110&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;/div&gt;Some additional information that influences the numbers (positively and negatively):&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Sometimes I work from home. &amp;nbsp;Occasionally I use remote desktop and work on my desktop where the count is recorded. &amp;nbsp;Some days I don't. &amp;nbsp;This could account for a lower count.&lt;/li&gt;&lt;li&gt;My work setup includes a laptop. &amp;nbsp;The laptop screens are set up next to the desktop screens and I use &lt;a href="http://synergy-foss.org/"&gt;Synergy &lt;/a&gt;to control both machines from a single keyboard/mouse, giving me a single, contiguous desktop (another tool I highly recommend). &amp;nbsp;The desktop serves as the Synergy server, acting as the input master which allows all input control going to the laptop to pass through the Workrave counters running on the desktop. &amp;nbsp;Occasionally, due to a glitch or a reboot, I won't have primary control so I'll physically switch to the laptop keyboard/mouse. &amp;nbsp;This could account for a reduction in keystroke count, though probably not much.&lt;/li&gt;&lt;li&gt;I haven't really been doing much programming lately, certainly not as much as in years past. &amp;nbsp;I do a lot of systems&amp;nbsp;administration, infrastructure&amp;nbsp;and other tasks that require less typing. &amp;nbsp;On days that I am actually writing code, my numbers jump significantly. &amp;nbsp;A safe estimate is an average in the 10,000 to 20,000 range, usually towards the high end.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;I took a look back over my daily numbers and journal entries for those high count days. &amp;nbsp;I found that the days I'm writing code, I average around 20,000 keystrokes. &amp;nbsp;So I can make a fairly safe prediction that if I spent most days writing code I would probably have numbers closer to these:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Daily Average: 20,000&lt;/li&gt;&lt;li&gt;Monthly Average: 418,333&lt;/li&gt;&lt;li&gt;Yearly Total: 5,020,000&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;That figure seems pretty crazy to me. &amp;nbsp;I never would have estimated in the millions if I'd been asked how many keystrokes I think I make in a year. &amp;nbsp;Considering that I've been a developer for a solid 11 years, and until recently, most of that has been spent programming, I would venture a guess that I have over 55 million keystrokes under my fingertips. &amp;nbsp;I have trouble fathoming that. &amp;nbsp;My typing teacher in high school would be proud.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-2579961017589649445?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/2579961017589649445/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=2579961017589649445' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/2579961017589649445'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/2579961017589649445'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2011/06/1-year-26-million-keystrokes.html' title='1 Year = 2.6 Million Keystrokes'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-8483659862288710324</id><published>2011-05-11T10:40:00.001-04:00</published><updated>2011-05-11T10:44:35.315-04:00</updated><title type='text'>Where I put my extension code</title><content type='html'>In a comment on my "&lt;a href="http://www.blogger.com/2011/02/aspnet-mvc-excluding-model-validation.html"&gt;ASP.NET MVC - Excluding Model Validation Rules&lt;/a&gt;" post reader @wow0609 asked:&lt;br /&gt;&lt;blockquote&gt;Where do you put something like this in your MVC project? This is a specific extension method, probably in a file by itself. Do you have a specific structure (directory / folder) you use for this? Do you have a generic /common folder or something?&lt;/blockquote&gt;&lt;br /&gt;I felt this question was worthy of a dedicated post.  I break it down this way.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Sharable Code&lt;/b&gt;&lt;br /&gt;If the code I've written is not specific to a particular application (as is the case of excluding model validation rules) then I will most likely put it into one of the shared libraries used by my development group. &amp;nbsp;Those libraries have lots of utility functions and such that are generic to the platform/stack they support. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Application Specific Code&lt;/b&gt;&lt;br /&gt;When the code is really only applicable to one application then I'll put it into the application's project. &amp;nbsp;For a web project I'll&amp;nbsp;typically&amp;nbsp;put them in a class under a "&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Components&lt;/span&gt;" directory. &amp;nbsp;Often, code will start here and then I'll refactor it to be more generic and move it to a shared library.&lt;br /&gt;&lt;br /&gt;In either case, for extension methods I usually name the class/file using this pattern: "&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;[extendedclass]Extensions"&lt;/span&gt;. &amp;nbsp;For example: &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;HtmlHelpersExtensions&lt;/span&gt;. &amp;nbsp;I set that class' namespace to the extended class' namespace. &amp;nbsp;In the case of the MVC model validation rule exclusion extension it would be "&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;System.Web.Mvc&lt;/span&gt;". &amp;nbsp;This eliminates the need to explicitly import/include the custom namespace to discover extension methods which is particularly helpful for shared libraries (or if you are like me and can't remember what you wrote last week).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-8483659862288710324?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/8483659862288710324/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=8483659862288710324' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/8483659862288710324'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/8483659862288710324'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2011/05/where-i-put-my-extension-code.html' title='Where I put my extension code'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-6172044212341843607</id><published>2011-02-04T12:16:00.005-05:00</published><updated>2011-02-04T13:01:11.650-05:00</updated><title type='text'>ASP.NET MVC - Excluding Model Validation Rules</title><content type='html'>While building a simple MVC app, I came across the problem where I am using one model in several views.  The model includes DataAnnotation attribute rules for validation.  However, some rules don't apply to certain views.  It seems this is a common problem, without a well established solution.  After searching a bit, I found &lt;a href="http://andrewtwest.com/2011/01/10/conditional-validation-with-data-annotations-in-asp-net-mvc/"&gt;this post by Andrew West&lt;/a&gt; that nicely summarizes the problem and several solutions.  His last suggestion is to remove the items from ModelState that you don't want to participate in the validation.  I agreed that this was the simplest and least dependent solution and pursued it.&lt;br /&gt;&lt;br /&gt;What I finally came up with was a simple extension method for the ModelStateDictionary that looks like this:&lt;br /&gt;&lt;pre&gt;public static void CleanAllBut(&lt;br /&gt;   this ModelStateDictionary modelState,&lt;br /&gt;   params string[] includes)&lt;br /&gt;   {&lt;br /&gt;      modelState&lt;br /&gt;        .Where(x =&gt; !includes&lt;br /&gt;           .Any(i =&gt; String.Compare(i, x.Key, true) == 0))&lt;br /&gt;        .ToList()&lt;br /&gt;        .ForEach(k =&gt; modelState.Remove(k));&lt;br /&gt;   }&lt;/pre&gt;&lt;br /&gt;The method removes everything in the model state dictionary that doesn't match one of the "includes" strings.  Being a params argument to the method, the call to it becomes very clean and readable (unlike the extension method itself).  So I added this call to my controller method:&lt;br /&gt;&lt;pre&gt;ModelState.CleanAllBut("username", "password");&lt;/pre&gt;&lt;br /&gt;While we can use the existing ModelStateDictionary.Remove() method for when we only want to explicitly remove one item, for multi-key removal we could make a similar extension method that takes a list of keys to remove.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-6172044212341843607?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/6172044212341843607/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=6172044212341843607' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/6172044212341843607'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/6172044212341843607'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2011/02/aspnet-mvc-excluding-model-validation.html' title='ASP.NET MVC - Excluding Model Validation Rules'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-7843479222041149522</id><published>2011-01-27T15:33:00.003-05:00</published><updated>2011-01-27T16:23:13.824-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='T4MVC'/><category scheme='http://www.blogger.com/atom/ns#' term='MVC'/><category scheme='http://www.blogger.com/atom/ns#' term='ASP.NET'/><title type='text'>Adding MVC view file extension exclusion to T4MVC</title><content type='html'>Yesterday I wrote about &lt;a href="http://www.compiledthoughts.com/2011/01/aspnet-mvc3-creating-razor-view-engine.html"&gt;creating razor view engine code behind files&lt;/a&gt;.  I've been playing with the &lt;a href="http://mvccontrib.codeplex.com/wikipage?title=T4MVC"&gt;T4MVC T4 template for ASP.NET MVC&lt;/a&gt; that I learned about by &lt;a href="http://channel9.msdn.com/posts/jongalloway/Jon-Takes-Five-with-David-Ebbo-on-T4MVC/"&gt;watching this video&lt;/a&gt;.  &lt;br /&gt;&lt;br /&gt;Today I discovered that the view code behind files I created are showing up in the MVC.&lt;i&gt;&amp;lt;controller&amp;gt;&lt;/i&gt;.Views list because the files (*.cs) are in the views folders next to the actual views (*.cshtml).  Due to the naming convention I used, the *.cs file comes first in the directory listing.  While the T4 template code gracefully deals with files with the same name portion of the full filename, the consequence of my names resulted in the generation of the following two properties:&lt;br /&gt;&lt;pre&gt;MVC.Shared.Views.PlantListPager&lt;br /&gt;MVC.Shared.Views.PlantListPager_cshtml&lt;/pre&gt;&lt;br /&gt;The first is the result of the code-behind file (PlantListPager.cs) while the second comes from the actual view (PlantListPager.cshtml).  Again, the template gracefully deals with a potential name conflict.  However, access to the code-behind path is not needed and the resulting extra property looks messy.&lt;br /&gt;&lt;br /&gt;I looked through the T4MVC.settings.t4 file and found the ExcludedStaticFileExtensions array of extensions that excludes the specified file extensions from property generation for the files found in the static folders (as specified by the StaticFilesFolders array just above it in the settings).  Unfortunately, I didn't find a similar array specifying exclusions for view folder(s)'s files.  Presumably, this is because the view folders would typically not have anything other than actual view files.  So I added the following block to the settings:&lt;br /&gt;&lt;pre&gt;// View file extensions to exclude from the generated links   &lt;br /&gt;readonly string[] ExcludedViewFileExtensions = new string[] {   &lt;br /&gt;    ".cs"&lt;br /&gt;};&lt;/pre&gt;&lt;br /&gt;In the T4MVC.tt template file, I found the code that excludes the static files in the "ProcessStaticFilesRecursive" method after which I modeled the following block that I added to the "AddViewsRecursive" method:&lt;br /&gt;&lt;pre&gt;if (ExcludedViewFileExtensions.Any(extension =&gt;&lt;br /&gt;     item.Name.EndsWith(extension, StringComparison.OrdinalIgnoreCase)))&lt;br /&gt;   continue;   // ignore defined extensions&lt;/pre&gt;&lt;br /&gt;This checks for extension exclusions when the list of views to create as properties is first built up.&lt;br /&gt;&lt;br /&gt;Now I realize that I should probably just contribute this change back into the &lt;a href="http://mvccontrib.codeplex.com/"&gt;MvcContrib project&lt;/a&gt;.  However, I'm going to cop out for the following reasons:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;  &lt;li&gt;I don't have the infrastructure tools and knowledge required (Mercurial &amp; NUnit)&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;I thought it would be valuable to illustrate how relatively simple it is to make a change to an existing T4 template without totally messing it up.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;If there's a T4MVC contributor out there reading this who'd like to include this change, by all means, please do.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-7843479222041149522?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/7843479222041149522/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=7843479222041149522' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/7843479222041149522'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/7843479222041149522'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2011/01/adding-mvc-view-file-extension.html' title='Adding MVC view file extension exclusion to T4MVC'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-3719603648248654994</id><published>2011-01-26T09:52:00.003-05:00</published><updated>2011-01-26T11:08:53.103-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MVC'/><category scheme='http://www.blogger.com/atom/ns#' term='ASP.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='Razor'/><title type='text'>ASP.NET MVC3 - Creating razor view engine code behind files</title><content type='html'>While code behind files are generally discouraged for MVC views, there are still times when it's helpful to have strongly typed and pre-compiled code to support a view when you have something more than rudimentary logic involved with view processing.&lt;br /&gt;&lt;br /&gt;In order for a single Razor view to have a code-behind file, it must be changed to inherit from another class instead of the default view page class, which is defined in the ~/Views/web.config as &lt;br /&gt;&lt;pre&gt;System.Web.Mvc.WebViewPage&lt;/pre&gt;&lt;br /&gt;The view base class is modified with this addition to the view's markup file:&lt;br /&gt;&lt;pre&gt;@inherits &lt;i&gt;&amp;lt;class name&amp;gt;&lt;/i&gt;&lt;/pre&gt;&lt;br /&gt;For example, a code-behind class for ~/Views/Home/Index.cshtml would be&lt;br /&gt;&lt;pre&gt;@inherits MySite.Views.Home.Index&lt;/pre&gt;&lt;br /&gt;If you have a model specified for the view using the @model nugget you must remove it from the view code and apply it to the new base class.&lt;br /&gt;&lt;br /&gt;Next, create a new class file for the code-behind class.  Following convention, it's probably best to put the file in the same directory as the view file itself and name it similarly.  I just grab the view's file name and drop the "html" from the extension.  Thus, following our example, we end up with:&lt;br /&gt;&lt;pre&gt;~/Views/Home/Index.cs&lt;br /&gt;~/Views/Home/Index.cshtml&lt;/pre&gt;&lt;br /&gt;The generated class file needs to be modified in these ways:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Set the base class to WebViewPage, or WebViewPage&amp;lt;&lt;i&gt;model type&lt;/i&gt;&amp;gt; if you had a model type specified in the view code.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Add "abstract" to the class definition (a concrete implementation of a WebViewPage derived class must implement the "Execute" method)&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;Continuing with our example we have a code-behind file for the Home/Index view that looks like this:&lt;br /&gt;&lt;pre&gt;namespace MySite.Views.Home&lt;br /&gt;   public abstract class Index : WebViewPage&lt;br /&gt;   {&lt;br /&gt;      // ... my super-duper code goes here&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Now code away!  Be sure to expose any methods you want to call from the view code as "protected" or "public" so they are visible to the view's derived class.&lt;br /&gt;&lt;br /&gt;Just remember that a view code-behind file is not a substitute for proper separation of concerns.  Remember to keep the code you place in a view code-behind class limited to only logic required to make the view do what it needs, no more.  Any code that starts to smell of business/application logic should be moved to the appropriate place, either a business library or a controller.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-3719603648248654994?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/3719603648248654994/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=3719603648248654994' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/3719603648248654994'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/3719603648248654994'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2011/01/aspnet-mvc3-creating-razor-view-engine.html' title='ASP.NET MVC3 - Creating razor view engine code behind files'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-437513739179478091</id><published>2011-01-15T23:18:00.013-05:00</published><updated>2011-01-18T09:56:41.457-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MVC'/><category scheme='http://www.blogger.com/atom/ns#' term='ASP.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='Razor'/><title type='text'>ASP.NET MVC Razor - AJAX partial page updating using views with default layout</title><content type='html'>ASP.NET MVC controller action methods that return views don't care whether that view is technically implemented as a full view or a partial view.  You can just as easily return a view created as a partial as easily as a standard, full view and the controller cares not.  Nor, it seems, does the view engine.  It will happily render out the content of the view as it is defined in its markup file.  This provides a handy mechanism by which a partial view can be used to perform partial page updates via AJAX.  An initial load of a full view can include a call to render a partial view, then a subsequent call from AJAX can explicitly return just the partial view.  I've used this technique several times with the original ASPX view engine and not had any issues.  However, once I started playing with the Razor view engine, I encountered a strange side effect.&lt;br /&gt;&lt;br /&gt;Both the ASPX and Razor view engines can define the master page/layout to use at a global level.  For ASPX it's in the web.config:&lt;br /&gt;&lt;pre&gt;&amp;lt;pages masterPageFile="~/Views/Shared/Site.Master"&amp;gt;&lt;br /&gt;   ...&lt;br /&gt;&amp;lt;/pages&amp;gt;&lt;/pre&gt;For Razor it's in the view start file for your chosen language, in my case it's C# (_ViewStart.cshtml):&lt;br /&gt;&lt;pre&gt;@{&lt;br /&gt;   Layout = "~/Views/Shared/_Layout.cshtml";&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;ASPX view engine partial views (*.ascx) include (apart from the obvious file extension difference) a specific directive instructing the view engine that it is a partial view (@ Control) and not a regular view (@ Page).  This causes the view engine to knowingly treat it as a partial view, rendering only its contents.  However, since Razor views are all the same there is no declaration to indicate that the view code in one .cshtml file is for a partial view versus a full view.  Any Razor view will have the same startup rules applied.&lt;br /&gt;&lt;br /&gt;When a Razor view is rendered as a partial from another view, such as:&lt;br /&gt;&lt;pre&gt;@Html.Partial("mypartialview")&lt;br /&gt;   or&lt;br /&gt;&amp;lt;% Html.RenderPartial("mypartialview"); %&amp;gt;&lt;/pre&gt;&lt;br /&gt;the view engine seems to recognize that the view is being loaded as a partial and (presumably) changes the inner view's Layout property to null and things work as desired.&lt;br /&gt;&lt;br /&gt;However, when you make an MVC action call that specifically loads JUST a partial view as the ViewResult with the intent of doing a partial page refresh, the results will differ based on the the view engine.  For an ASPX engine partial view (i.e. *.ascx) the view will load and render as is.  It contains no references to a master page and the view engine knows explicitly that it is a "@ Control" and thus does not wrap it in any default master page, if one is defined.  On the other hand, a Razor view is loaded as any other view and will include the master layout set by default.  What is intended as a partial page update will actual return with all of the layout pages HTML around it.  In order to keep a Razor view as a partial view, any existing value for the view's Layout property must be negated.  This code can be placed in a code block of any view that is intended to be a partial view:&lt;br /&gt;&lt;pre&gt;@{&lt;br /&gt; this.Layout = null;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;This will cancel out any default master layout setting and render the view with &lt;span style="font-style:italic;"&gt;only&lt;/span&gt; that view's contents.  When the same view is included in another view as a partial, the above code will have not effect since the calling view has already nulled out the layout file anyway.&lt;br /&gt;&lt;br /&gt;If you wanted to, you could use a view for either a full view (with the default layout's content) or a partial view by conditionally nulling out the Layout property based on some view data set by an appropriate controller action.  Combined with a parameter passed in by the AJAX caller, this could provide a useful mechanism for reusing view elements.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-437513739179478091?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/437513739179478091/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=437513739179478091' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/437513739179478091'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/437513739179478091'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2011/01/aspnet-mvc-razor-partial-views-with.html' title='ASP.NET MVC Razor - AJAX partial page updating using views with default layout'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-4898879167191640334</id><published>2011-01-14T10:00:00.004-05:00</published><updated>2011-01-14T10:37:32.220-05:00</updated><title type='text'>Doing 2+ aggregations in LINQ to SQL</title><content type='html'>I was recently trying to do a simple double aggregation using LINQ to SQL.&lt;br /&gt;&lt;br /&gt;Here's the setup:&lt;br /&gt;&lt;br /&gt;One table "Plant" containing these two fields of concern: &lt;br /&gt;&lt;pre&gt;  ZoneMin tinyint&lt;br /&gt;  ZoneMax tinyint&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;There's a search view on which I want to include the selection of a range for each of those fields.  Therefore, I want to select the minimum and maximum of each field.  In T-SQL this would be trivial:&lt;br /&gt;&lt;pre&gt;SELECT&lt;br /&gt;  MIN(ZoneMin) MinMin, MAX(ZoneMin) MinMax,&lt;br /&gt;  MIN(ZoneMax) MaxMin, MAX(ZoneMax) MaxMax&lt;br /&gt;FROM Plant&lt;/pre&gt;&lt;br /&gt;I tried numerous approaches with the .Aggregate() method, grouping and everything else I could think of.  No luck.  I finally broke down and &lt;a href="http://stackoverflow.com/questions/4672239/select-minzonemin-maxzonemin-from-plant-as-linq-to-sql"&gt;posted to StackOverflow&lt;/a&gt; and got a simple answer.  The end result is this LINQ query:&lt;br /&gt;&lt;pre&gt;Plants.GroupBy (p =&gt; 0).Select (p =&gt; new { &lt;br /&gt; MinMin = p.Min (x =&gt; x.ZoneMin), &lt;br /&gt; MinMax = p.Max (x =&gt; x.ZoneMin),&lt;br /&gt; MaxMin = p.Min (x =&gt; x.ZoneMax), &lt;br /&gt; MaxMax = p.Max (x =&gt; x.ZoneMax)&lt;br /&gt;})&lt;/pre&gt;&lt;br /&gt;This yields the following T-SQL (courtesy of LINQPad):&lt;br /&gt;&lt;pre&gt;-- Region Parameters&lt;br /&gt;DECLARE @p0 Int = 0&lt;br /&gt;-- EndRegion&lt;br /&gt;SELECT &lt;br /&gt;    MIN([t1].[ZoneMin]) AS [MinMin], MAX([t1].[ZoneMin]) AS [MinMax], &lt;br /&gt;    MIN([t1].[ZoneMax]) AS [MaxMin], MAX([t1].[ZoneMax]) AS [MaxMax]&lt;br /&gt;FROM (&lt;br /&gt;    SELECT @p0 AS [value], [t0].[ZoneMin], [t0].[ZoneMax]&lt;br /&gt;    FROM [Plant] AS [t0]&lt;br /&gt;    ) AS [t1]&lt;br /&gt;GROUP BY [t1].[value]&lt;/pre&gt;&lt;br /&gt;Comparing the two execution plans (Query 2 is LINQ and Query 3 is T-SQL) shows that they are the same:&lt;br /&gt;&lt;br /&gt;&lt;img style="width: 502px; height: 249px;border:1px solid black;" src="http://4.bp.blogspot.com/_1ODj8s-E01o/TTBqzup_vxI/AAAAAAAAA68/FT0Wj13KBds/s1600/ExecPlanComparison.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5562062976732610322" /&gt;&lt;br /&gt;&lt;br /&gt;So the lesson here is: remember to try constant value grouping.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-4898879167191640334?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/4898879167191640334/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=4898879167191640334' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/4898879167191640334'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/4898879167191640334'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2011/01/doing-2-aggregations-in-linq-to-sql.html' title='Doing 2+ aggregations in LINQ to SQL'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_1ODj8s-E01o/TTBqzup_vxI/AAAAAAAAA68/FT0Wj13KBds/s72-c/ExecPlanComparison.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-6606193976857821108</id><published>2010-02-19T15:17:00.007-05:00</published><updated>2010-02-19T16:33:45.923-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='web development'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='IIS'/><category scheme='http://www.blogger.com/atom/ns#' term='ASP.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='Windows7'/><title type='text'>Developing on Windows 7: ASP.NET Security in IIS 7</title><content type='html'>I've recently gotten a new development machine at work.  I've been using a laptop with a 1.8GHz dual core Centrino, 2 gigs of RAM and Windows XP Pro x86.  After months of pushing, I finally got them to get us secondary machines.  So in addition to the laptop which is now just an "office productivity" machine (i.e. Outlook and surfing YouTube ;-) I now do my development on a desktop with a 2.9GHz Core2 Duo, 8 gigs of RAM and Windows 7 Pro x64.  (A bit of an improvement.)&lt;br /&gt;&lt;br /&gt;As I explore the transition to Windows 7 I'm discovering the nuances of developing on a 64 bit platform and running ASP.NET sites in IIS7.  Fortunately, the move to 64 bits has been a non issue as suggested by &lt;a href="http://twitter.com/brianpeek"&gt;Brian Peek&lt;/a&gt; in &lt;a href="http://www.dotnetrocks.com/default.aspx?showNum=341"&gt;his DotNet Rocks interview&lt;/a&gt;.  IIS7 has been a bit more of a change.&lt;br /&gt;&lt;br /&gt;Apart from the significant change to the administrative console for IIS 7 there are some aspects of it that introduce so new behaviors when running ASP.NET applications.  I'm no expert of IIS, but I know that the jump from IIS 6 to 7 has brought in a much higher level of .NET integration.  .NET is really a first class citizen in the world of IIS 7 much like it is in Windows 7 all around.&lt;br /&gt;&lt;br /&gt;I typically run the sites I'm developing in IIS instead of the built in Visual Studio web server so I can more accurately reflect the eventual environment on which the sites will run in testing and production.  Notably, the influences of security of the IIS service compared to running the local dev web server process under my highly privileged user account.  I've answered more than one forum post asking why a site can't write to a file resource when it's deployed to the web hosting environment running a standard IIS process.  For that reason I almost always make the change to hosting a developing site in IIS when I first create a new web application project.&lt;br /&gt;&lt;br /&gt;While developing a new site using the MVC framework I activated web forms security to set up the login.  After refreshing the browser all my styles were gone!  Being new to MVC I figured I was doing something wrong.  However, I was using the MVC's template login page, master page and CSS file so I didn't think that I had messed anything up.  A quick "view-source" and click on the referenced CSS file brought me back to the login page.  At that point I realized that the CSS file was being blocked by the web forms security settings.  A few bounces around my head between "wait a minute, CSS files aren't served by the ASP.NET process" to "this is acting like the dev web server" to "oh yeah, Win 7 == IIS 7 and IIS 7 has way more .NET baked into it."&lt;br /&gt;&lt;br /&gt;With the higher level of .NET integration in IIS 7 comes the full scrutiny of a given web applications security settings.  So the authorization rules I activated in the application's web.config now are affecting any file served from that web, regardless of whether it's being processed by the ASP.NET runtime.  In this case the entire application was denied for un-authenticated users, thus the CSS file request was redirecting to the logon page.&lt;br /&gt;&lt;br /&gt;A simple solution is to put all your non-protected content files (css, images, possibly JS) in a directory that contains a secondary web.config that overrides the main config's security:&lt;br /&gt;&lt;pre&gt;&amp;lt;?xml version="1.0"?&amp;gt;&lt;br /&gt;&amp;lt;configuration&amp;gt;&lt;br /&gt;  &amp;lt;system.web&amp;gt;&lt;br /&gt;    &amp;lt;authorization&amp;gt;&lt;br /&gt;      &amp;lt;allow users="*" /&amp;gt;&lt;br /&gt;    &amp;lt;/authorization&amp;gt;&lt;br /&gt;  &amp;lt;/system.web&amp;gt;&lt;br /&gt;&amp;lt;/configuration&amp;gt;&lt;/pre&gt;&lt;br /&gt;This will allow unauthenticated users access to resources in the directory (and child directories) this file lives in.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-6606193976857821108?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/6606193976857821108/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=6606193976857821108' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/6606193976857821108'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/6606193976857821108'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2010/02/developing-on-windows-7-aspnet-security.html' title='Developing on Windows 7: ASP.NET Security in IIS 7'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-2722045889915682074</id><published>2009-12-30T11:00:00.002-05:00</published><updated>2009-12-30T11:02:01.217-05:00</updated><title type='text'>Reflecting on "invisible" accessors</title><content type='html'>I was writing a unit test for a utility that writes to a class&lt;br /&gt;property.  The utility first checks that the property can be written&lt;br /&gt;to (PropertyInfo.CanWrite == true) and throws an access exception if&lt;br /&gt;not writable.  The test was to check for the expected exception.&lt;br /&gt;Theoretically, if the property is read-only, the test should pass&lt;br /&gt;(i.e. property is not writable).&lt;p&gt;First I tried an automatic property with a private setter:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    public string Arg { get; private set; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;FAILED!&lt;p&gt;Then I tried a standard property with backing var and a private setter:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    private string _arg;&lt;br /&gt;    public string Arg {&lt;br /&gt;        get { return _arg; }&lt;br /&gt;        private set { _arg = value; }&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;FAILED&lt;p&gt;Finally, I removed the setter altogether:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    private string _arg;&lt;br /&gt;    public string Arg {&lt;br /&gt;        get { return _arg; }&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;PASSED&lt;p&gt;It seems that even though the setter is private, reflection still sees&lt;br /&gt;it and allows writing to it.  Rather strange.  In my case it&amp;#39;s not a&lt;br /&gt;big deal, because I want to be able to write to the property which&lt;br /&gt;I&amp;#39;ll be able to do as long as a setter is present.  However, it could&lt;br /&gt;result in a strange bug for the utility consumer.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-2722045889915682074?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/2722045889915682074/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=2722045889915682074' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/2722045889915682074'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/2722045889915682074'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2009/12/reflecting-on-invisible-accessors.html' title='Reflecting on &quot;invisible&quot; accessors'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-5578254711143814178</id><published>2009-10-12T14:51:00.013-04:00</published><updated>2009-10-12T15:47:52.834-04:00</updated><title type='text'>Visual Studio Tool Windows on Mimo USB Monitor</title><content type='html'>I love multiple screens.  My work machine is a laptop.  Fortunately the model I have does have dual external display capabilities when using the docking station so I'm able to run two standard desktop screens.  However, being a developer, geek and generally greedy hardware guy, I wanted more.  Since I am limited to two standard video connections I thought I was stuck.  Until &lt;a href="http://www.thinkgeek.com/computing/usb-gadgets/bfa3/"&gt;ThinkGeek.com&lt;/a&gt; came to the rescue.&lt;br /&gt;&lt;br /&gt;So several weeks ago I got the &lt;a href="http://www.mimomonitors.com/"&gt;Mimo&lt;/a&gt; UM-710 USB mini monitor.  It's connected by nothing but a standard USB connection.  One of the ideas I had was to be able to use it for some of the ancillary apps and widgets I run that I'd like to have in view, but not occupy standard main screen real estate.  Things such as music players, tool windows, email, etc.&lt;br /&gt;&lt;br /&gt;Scott Hanselman has a &lt;a href="http://www.hanselman.com/blog/ReviewMimoMonitorsIMoPivot.aspx"&gt;good entry about his mimo&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;For quite a while now I've been running two multiscreen windows tools: &lt;a href="http://www.realtimesoft.com/ultramon/"&gt;UltraMon&lt;/a&gt; and &lt;a href="http://www.winsplit-revolution.com/"&gt;Winsplit Revolution&lt;/a&gt;.  Among other things, UltraMon&lt;br /&gt;provides multi monitor windows task bars (most stable implementation that I've found so far and worth the price).  It also has shortcut keys for manipulating windows on your desktop (move screen to screen, minimize, maximize).  Winsplit Revolution (free!) provides similar and additional window manipulation using key shortcuts.&lt;br /&gt;&lt;br /&gt;Getting back to the main topic, I can use the two multi-screen tools to manipulate Visual Studio tool windows.  If you undock a VS tool window, it can be easily moved to another screen with traditional methods (i.e. the ever inefficient mouse).  However, because these windows are implemented as a tool window which is traditionally floating or docked to the main IDE window, there are no commands or buttons to maximize it to the usable screen size.  Here's what I end up with after moving the Test Results window to my Mimo:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_1ODj8s-E01o/StOBTMniTmI/AAAAAAAAAOc/COcfNd2CqKE/s1600-h/Floating.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 240px;" src="http://4.bp.blogspot.com/_1ODj8s-E01o/StOBTMniTmI/AAAAAAAAAOc/COcfNd2CqKE/s400/Floating.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5391795345697164898" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Sure you could use your mouse to move the window to the top left, then resize it to the bottom right, but who has that many cycles to waste?  That's where the windowing tools come into play.  I can undock a tool window from the IDE, and while focused on it, use the shortcut key CTRL-ALT-[Left/Right Arrow] to shuffle the window to an adjacent monitor.  Then, while keeping the modifier keys pressed, I can just hit the Up Arrow key to maximize the window to the screen.  Using Winsplit Revolution I can actually use the same key sequence in reverse.  Winsplit respects location and position proportioning so it will move the window to a relatively similar position/size when moving between disparate screen sizes.  After this move and resize, my Mimo screen looks like this:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_1ODj8s-E01o/StOBn-kriiI/AAAAAAAAAOk/OWku7Wc0v3k/s1600-h/WinSplitMax.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 240px;" src="http://4.bp.blogspot.com/_1ODj8s-E01o/StOBn-kriiI/AAAAAAAAAOk/OWku7Wc0v3k/s400/WinSplitMax.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5391795702704343586" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Notice the problem here? The window has been sized to the maximum &lt;span style="font-style:italic;"&gt;screen&lt;/span&gt; space, not the maximum usable &lt;span style="font-style:italic;"&gt;desktop&lt;/span&gt; space.  Note the previous screenshot which includes the horizontal scrollbar.  This isn't that major of a problem, but it's still annoying.&lt;br /&gt;&lt;br /&gt;However, there's an easy fix.  Instead of using the "Maximize" shortcut key in Winsplit, I use the "Center" shortcut.  This shortcut positions the active window to the center of the screen in several increments.  The window always assumes full usable desktop height, with respect to the taskbar.  However, it will take up one of three percentages of the screen width: 33%, 66% or 100%.  Fortunately, it does 100% first.  So when "Center"ed to the first step, the tool window is actually sized to the full desktop space. However, it's not actually maximized in the true sense so you get the window border.  But this is a small cost for being able to see and access the whole window.  After using the Winsplit "Center" shortcut, I end up with this:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_1ODj8s-E01o/StODm3Dpd2I/AAAAAAAAAOs/Tyujgqy4yGs/s1600-h/WinSplitCenter.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 240px;" src="http://2.bp.blogspot.com/_1ODj8s-E01o/StODm3Dpd2I/AAAAAAAAAOs/Tyujgqy4yGs/s400/WinSplitCenter.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5391797882530133858" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Winsplit can also place windows into the corners of the screen with a single key combo.  Also handy if you have several windows you want to tile into some screen space without using the built in windows methods which mess with everything.&lt;br /&gt;&lt;br /&gt;Even if you don't have a Mimo, or even multiple monitors, get Winsplit Revolution, it's free and it rocks!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-5578254711143814178?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/5578254711143814178/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=5578254711143814178' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/5578254711143814178'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/5578254711143814178'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2009/10/visual-studio-tool-windows-on-mimo-usb.html' title='Visual Studio Tool Windows on Mimo USB Monitor'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_1ODj8s-E01o/StOBTMniTmI/AAAAAAAAAOc/COcfNd2CqKE/s72-c/Floating.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-6511275390904911501</id><published>2009-05-21T16:03:00.002-04:00</published><updated>2009-05-21T16:07:31.178-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='ASP.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio'/><title type='text'>Stringy stringy bang bang</title><content type='html'>I had a simple scenario: Array of strings bound to a GridView.  Initially, with auto generation of columns, this is easy.  You get a single column with all the strings in the array.  But then I needed to do something practical with it, so thus needed to specify the columns:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  &amp;lt;Columns&amp;gt;&lt;br /&gt;     &amp;lt;asp:BoundField DataField="?????" /&amp;gt;&lt;br /&gt;     ...&lt;br /&gt;  &amp;lt;/Columns&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I noticed that the column header said "Item" when auto generated so I tried that, but it didn't work.  So then, I ask myself, what is the data field of a System.String?  The only bindable member (public field or property) is .Length.  Good to know but useless in this case.  The ToString() member is a method so it can't be bound to.  But apparently there is an undocumented trick: Use the exclamation point (!) as the datafield value and you'll get the string's value.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; &amp;lt;asp:BoundField DataField="!" /&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This yields the desired result.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-6511275390904911501?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/6511275390904911501/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=6511275390904911501' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/6511275390904911501'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/6511275390904911501'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2009/05/stringy-stringy-bang-bang.html' title='Stringy stringy bang bang'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-3619608285287132821</id><published>2009-04-23T13:30:00.002-04:00</published><updated>2009-04-23T13:36:56.523-04:00</updated><title type='text'>Understanding MS SQL Server Named Instance Connections</title><content type='html'>I had had several discussions in the past with a systems engineer about why the MS SQL Server named instances he had set up in various environments were using non-standard ports.  I explained that the whole idea of named instances was to eliminate that need.  He couldn't explain why he needed non-standard ports, just that he did.  Of course, that didn't satisfy my curiosity but I dismissed it until now.&lt;br /&gt;&lt;br /&gt;I was recently setting up several new instances of SQL Server on a machine in our data center that already has a default instance on it. As such, I created all the new ones as named instances.  All was well and good.  I connected to the new instances from the local machine (presumably using the default shared memory connection) and continued configuring the instances including enabling the TCP/IP protocol.  I did all of this work via remote desktop on the machine itself.&lt;br /&gt;&lt;br /&gt;Then it came time to connect to these new instances from my local environment through the corporate network firewall(s) using SQL management studio.  The existing instance connected fine.  But none of the new named instances would connect.  I was puzzled and irritated. Obviously, the standard SQL port (1433) was open through the firewall&lt;br /&gt;to that box, as I could connect to the default instance.  So what was going on?&lt;br /&gt;&lt;br /&gt;After a bit of reading, digging further into the instance configurations and a conversation with a co-worker, I learned about dynamic ports.  Here's how it works:&lt;br /&gt;&lt;br /&gt;When you connect to a server using a default instance configuration (e.g. "myserver"), the SQL client calls the server on the standard port: 1433.  In my case, this was fine, the port was open through the firewall.  When you call a server using a named instance but lacking a port (e.g. "myserver\instancename"), the SQL client calls SQL Server's management service on port 1434.  The management service replies with a dynamically assigned port (chosen at sql engine service startup) for the instance and the client connection proceeds using that new port. In my case, the network firewall doesn't have either the management service port nor the dynamic port(s) open.  So my connections failed.&lt;br /&gt;&lt;br /&gt;Using dynamic ports for SQL instances basically means that the instance names are like a SQL DNS system.  They are simply there to help the server resolve a dynamic port.  Once the port is resolved, the name is superfluous.&lt;br /&gt;&lt;br /&gt;This brought me to the actual reason that the systems engineer had to use additional, and thus non-standard, ports for the additional SQL instances.  He needed to have known ports so the firewall could be configured to allow them.&lt;br /&gt;&lt;br /&gt;On further investigation I learned that once you have a predefined port assigned to a named instance you no longer need the actual instance name for the connection.  You can simply connect using the server name (or IP) and port number, for example: "myserver,1432". Also, once you are connecting using predefined port(s) you no longer&lt;br /&gt;need to run the SQL browser service on the server that provides the instance name lookup, thus freeing up a few system resources. &lt;br /&gt;&lt;br /&gt;So the simple solution to my original problem was to assigned specific ports to the various instances on the machine.  It turned out that the first non-standard port I used, 1432, was already open through the firewall so I could connect to the existing default instance and one of the new named instances remotely without having to request a firewall change.  The other instances aren't as critical to have outside connectivity to so I can worry about those later.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-3619608285287132821?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/3619608285287132821/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=3619608285287132821' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/3619608285287132821'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/3619608285287132821'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2009/04/understanding-ms-sql-server-named.html' title='Understanding MS SQL Server Named Instance Connections'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-8420945807895053814</id><published>2009-01-31T22:07:00.013-05:00</published><updated>2009-01-31T23:20:50.773-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><category scheme='http://www.blogger.com/atom/ns#' term='LINQ'/><category scheme='http://www.blogger.com/atom/ns#' term='database'/><title type='text'>Adventures in LINQ: Deferred execution</title><content type='html'>I recently started a new project in ASP.NET 3.5.  It actually a total re-write of an old application I created some time ago.  I haven't done any significant web development since the official release of 3.5 (hard to believe) so I needed to get back on the horse and get up to speed.  One of the goals is to get familiar with LINQ.  One of my co-workers used it for a project we architected and he said that LINQ saved boat loads of effort so I figured it was high time for me to get my act together.&lt;br /&gt;&lt;br /&gt;One of the first things I've discovered with LINQ is how chatty it is with the database server.  After starting to experiment with LINQ I turned on the SQL Server Profiler so I could watch what LINQ was doing with the database.  I noticed far more queries being executed than I'd have expected.  Way more than I would execute myself if I were programming the traditional way with my own explicitly defined queries.  A key source of the excessive query traffic is the concept of deferred execution.&lt;br /&gt;&lt;br /&gt;Here's how it plays out.  I have my digital photos in a file repository on disk.  I'm building a database driven tagging system for them.  In my photo library database, I have a table called "Photo".  This abstracts out to the "Photos" class in the LINQ to SQL classes DBML.  I need to scan the file repository for new photos and check the database to see if they already exist.  Simple enough.  For each photo file I encounter I want to check the database.  It stands to reason that I shouldn't query the DB for each individual file, but rather preload the photo table to an in memory collection then look through the collection for each photo that's encountered.  So I approach it this way:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;01  string[] strFiles;&lt;br /&gt;02  strFiles = Directory.GetFiles(dirPath, "*.*");&lt;br /&gt;03&lt;br /&gt;04  var lstPhotos = from p in _db.Photos select p;&lt;br /&gt;05  for(int i = 0; i &lt; strFiles.Length; i++)&lt;br /&gt;06  {&lt;br /&gt;07    intPhotoCount = (from p in lstPhotos &lt;br /&gt;08       where p.RelativePath == strFiles[i] &lt;br /&gt;09       select p).Count();&lt;br /&gt;10    if(intPhotoCount == 0)&lt;br /&gt;11    {&lt;br /&gt;12      // do create photo stuff&lt;br /&gt;13    }&lt;br /&gt;14  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;What I expected to see was a single query fired against the database at line 04.  But I didn't.  Instead, I got one query for each iteration of the loop, fired at line 07-09.  This query, as suggested by the LINQ, contained an explicit 'where' clause for the RelativePath value test.  &lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  exec sp_executesql N'SELECT COUNT(*) AS [value]&lt;br /&gt;  FROM [dbo].[Photo] AS [t0]&lt;br /&gt;  WHERE [t0].[RelativePath] = @p0',&lt;br /&gt;  N'@p0 varchar(30)',@p0='&lt;photo file&gt;.JPG'&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;With many thousands of photos, this isn't good.  So I thought that maybe if I forced the data context into delivering a full set the collection would preload as I planned.  I added this line immediately after the initial LINQ (after line 04):&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  lstPhotos.GetEnumerator();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;When I ran this, I saw this SQL execute:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  SELECT [t0].[PhotoId], [t0].[CollectionId]&lt;br /&gt;    , [t0].[RelativePath], [t0].[Title]&lt;br /&gt;    , [t0].[Description], [t0].[Height], [t0].[Width]&lt;br /&gt;  FROM [dbo].[Photo] AS [t0]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Great!  However, it's immediate followed up by the same loop specific queries.  All I did was add a superfluous query to the noise.  The GetEnumerator() call got me thinking that I could use the actual resulting enumerator.  However, my original approach was: for each file encountered, check the existing photo list from the database to see if I've already captured it.  In order to use the enumerator, I have to reverse the tactic because we can't find a single item using an enumerator, only go through the enumerator's set front to back.&lt;br /&gt;&lt;br /&gt;So let's reverse the approach.  Instead of iterating through the file list, we'll go through the LINQ result set.  Then I'll remove the file item that matches.  The result will be the files that don't yet exist in the database.  We can then add those.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;01  List&lt;string&gt; lstFiles = new List&lt;string&gt;(strFiles);&lt;br /&gt;02  var lstPhotos = from p in _db.Photos select p;&lt;br /&gt;03  foreach(Photo photo in lstPhotos)&lt;br /&gt;04  {&lt;br /&gt;05    lstFiles.Remove(photo.RelativePath);&lt;br /&gt;06  }&lt;br /&gt;07  if(lstFiles.Count &gt; 0)&lt;br /&gt;08  {&lt;br /&gt;09    for(int i = 0; i &lt; lstFiles.Count; i++)&lt;br /&gt;10    {&lt;br /&gt;11      // do new photo stuff&lt;br /&gt;12    }&lt;br /&gt;13  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;First I create a generic collection out of the original file name string array (return type of Directory.GetFiles()).  After the LINQ for the complete result set from Photos, I do a foreach, which calls .GetEnumerator() on lstPhotos.  This results in a single SQL query for the entire result set.  Then I iterate through the results, removing any matches.  Last, I do the actual creation of the remaining items.&lt;br /&gt;&lt;br /&gt;I find more and more with .NET that I must work as though I'm carving an ice sculpture.  Instead of trying to build something up with little cubes it's often easier to start with a single large block and take away what you don't need.  This is a surprisingly applicable analogy.  While you need a lot more space (memory) to start with the large block of ice (data), once you've chipped away what you don't need, it's easily cleaned up (garbage collection).  The alternative is a process that takes considerably longer and may ultimately be more fragile in the end.&lt;br /&gt;&lt;br /&gt;It's amazing how often thinking backwards can lead to a better solution.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-8420945807895053814?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/8420945807895053814/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=8420945807895053814' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/8420945807895053814'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/8420945807895053814'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2009/01/adventures-in-linq-deferred-execution.html' title='Adventures in LINQ: Deferred execution'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-4607968921284986222</id><published>2008-11-03T21:13:00.005-05:00</published><updated>2008-11-03T21:31:02.246-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bugs'/><category scheme='http://www.blogger.com/atom/ns#' term='technology'/><title type='text'>Google vote map wins 3 to 1, but I'll had to drive 3 hours</title><content type='html'>Apparently "Pulaski" is a common Ukrainian name, and they like to put American Citizens Clubs on streets with that name.&lt;br /&gt;&lt;br /&gt;I saw &lt;a href="http://twitter.com/shanselman"&gt;Scott Hanselmans&lt;/a&gt;'s &lt;a href="http://twitter.com/shanselman/status/988072846"&gt;tweet&lt;/a&gt; about &lt;a href="http://maps.google.com/vote"&gt;Google's 2008 US Voter Info map&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;For the heck of it, I tried my current address and 3 places I used to live, one of which being the town of Cohoes, outside of Albany NY (the capital city, in what is considered to be upstate NY).&lt;br /&gt;&lt;br /&gt;Google suggested that I drive 170 mi to the Ukrainian American Citizens Club on Pulaski Avenue in Staten Island.  Interestingly, the place I *did* vote 4 years ago was the Ukrainian American Citizens Club on Pulaski &lt;span style="font-style:italic;"&gt;Street&lt;/span&gt; in Cohoes, NY.  They had the right place, (almost) the right street name, just the wrong city.  &lt;br /&gt;&lt;br /&gt;It's a good thing I moved, or I'd have to forfeit my vote as the absentee ballot probably wouldn't get there in time.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-4607968921284986222?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/4607968921284986222/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=4607968921284986222' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/4607968921284986222'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/4607968921284986222'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2008/11/google-vote-map-wins-3-to-1-but-ill-had.html' title='Google vote map wins 3 to 1, but I&apos;ll had to drive 3 hours'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-9126896893456323958</id><published>2008-10-15T09:04:00.004-04:00</published><updated>2008-10-15T09:15:34.144-04:00</updated><title type='text'>Tron guy is a PC</title><content type='html'>Who says Microsoft doesn't have a sense of humor?  Not only are they copying the image of John Hodgman's buttoned up "PC" from the Mac ads, a recent marketing email (obviously a long delayed rebuttal to those ads which accompanies the TV ad series) includes a thumbnail of none other than the &lt;a href="http://www.tronguy.net"&gt;Tron guy&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_1ODj8s-E01o/SPXrDGj6yUI/AAAAAAAAAEo/661_zGaF47Y/s1600-h/MicrosoftTronGuy.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://2.bp.blogspot.com/_1ODj8s-E01o/SPXrDGj6yUI/AAAAAAAAAEo/661_zGaF47Y/s400/MicrosoftTronGuy.png" alt="" id="BLOGGER_PHOTO_ID_5257366578558323010" 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/13073408-9126896893456323958?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/9126896893456323958/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=9126896893456323958' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/9126896893456323958'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/9126896893456323958'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2008/10/tron-guy-is-pc.html' title='Tron guy is a PC'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_1ODj8s-E01o/SPXrDGj6yUI/AAAAAAAAAEo/661_zGaF47Y/s72-c/MicrosoftTronGuy.png' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-815652458339781002</id><published>2008-10-02T22:14:00.004-04:00</published><updated>2008-10-02T22:39:27.712-04:00</updated><title type='text'>Sometimes Google scares me</title><content type='html'>My parents just got a new dog.  They sent me a short note about it when it came home for the first time.  In the email the following words are mentioned that relate to dogs within the context of the message, those that could be understood to have to do with dogs &lt;span class="Apple-style-span" style="font-style: italic;"&gt;outside&lt;/span&gt; the message context are in &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;bold&lt;/span&gt;:&lt;div&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_1ODj8s-E01o/SOWBfZ9K7wI/AAAAAAAAAEI/ejBpT1TSZQ8/s1600-h/DogAds.png"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_1ODj8s-E01o/SOWBfZ9K7wI/AAAAAAAAAEI/ejBpT1TSZQ8/s400/DogAds.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5252746916940934914" /&gt;&lt;/a&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;spayed&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;standard poodle&lt;/span&gt;&lt;/li&gt;&lt;li&gt;lab&lt;/li&gt;&lt;li&gt;brush&lt;/li&gt;&lt;li&gt;paw&lt;span class="Apple-style-span" style="font-weight: bold;"&gt; &lt;/span&gt;(lots of animals have paws, and it's a verb)&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;My &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;gmail&lt;/span&gt; account showed some ads as it always does, they can be seen to the right.  This was one of the rare &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_1"&gt;occasions&lt;/span&gt; that I actually looked at them.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Among the ads is one for "Australian &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;Labradoodles&lt;/span&gt;".   My parent's new dog just happens to be a lab poodle mix.  However, nowhere in the message is that mentioned apart from the simultaneous occurrence of "lab" with "poodle" in the message.  Obviously though, any &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_3"&gt;astute&lt;/span&gt; advertiser would pair those words for their &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;labradoodle&lt;/span&gt; business.  Interestingly though, none of the ads seem to directly deal with having animals fixed.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It just amazes me how &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_5"&gt;accurate&lt;/span&gt; the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;google&lt;/span&gt; ads can be given so little to go on.  I recently finished reading "&lt;a href="http://www.thegooglestory.com/"&gt;The Google Story&lt;/a&gt;" which explains a bit about the general ideas behind &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_7"&gt;google's&lt;/span&gt; methodologies of search ranking, but doesn't say too much about it's ad matching techniques apart from the word bidding concepts (understandably).  (Very good book, by the way, I highly recommend it.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I wonder how similar the results would be if I wrote an email saying:&lt;/div&gt;&lt;div&gt;&lt;blockquote&gt;&lt;/blockquote&gt;&lt;blockquote&gt;After I brush my teeth I'm going to paw through a catalog then take the poodle to be spayed.&lt;/blockquote&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-815652458339781002?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/815652458339781002/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=815652458339781002' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/815652458339781002'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/815652458339781002'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2008/10/sometimes-google-scares-me.html' title='Sometimes Google scares me'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_1ODj8s-E01o/SOWBfZ9K7wI/AAAAAAAAAEI/ejBpT1TSZQ8/s72-c/DogAds.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-4502135373537879807</id><published>2008-09-10T09:14:00.008-04:00</published><updated>2008-09-10T09:34:39.116-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='web development'/><category scheme='http://www.blogger.com/atom/ns#' term='IIS'/><category scheme='http://www.blogger.com/atom/ns#' term='Windows'/><title type='text'>Identifying servers in a web farm with IIS headers</title><content type='html'>Once your application has been deployed to a web server farm, it can become tricky to track down problems.  Particularly when a problem occurs intermittently.  Sometimes these intermittent problems are such because they are occurring on only one machine of a web farm.  &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Identifying the problem server can be rather challenging.  Often the first attempt is to modify your local DNS (in Windows it's the HOSTS file) to point the site URL to a single machine.  Depending on how your web farm is set up you may not be able to do this because the individual machines may not be visible to you.  Only the farm's pool address is visible.  Furthermore, sometimes the problems we encounter do not manifest themselves when running on a single environment (otherwise we'd have caught them in development right??).  To complicate the matters moreso, often the only chance you have to identify on which machine the problem occurred is right when it occurred, as in, when you are staring at the application crash page.  Simply attempting to replicate the problem after you set up your tracking may not be enough.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A simple solution I have implemented on our staging and production web farms involves nothing more than the built in HTTP headers supplied by IIS.  First, just add an HTTP header to each machine in the farm that contains the name of the machine, or any other unique value that you can map to the machine:&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_1ODj8s-E01o/SMfMVN0QdLI/AAAAAAAAADc/d1U9uX1Wd2c/s1600-h/ServerNameHeader-IIS.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_1ODj8s-E01o/SMfMVN0QdLI/AAAAAAAAADc/d1U9uX1Wd2c/s400/ServerNameHeader-IIS.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5244384955954394290" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Then, when you browse to the site or are looking at an error message, you can open a tool like Fiddler or FireBug to view the page's HTTP header information for the response.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_1ODj8s-E01o/SMfMghs6EQI/AAAAAAAAADk/PlnUkqDxiWY/s1600-h/ServerNameHeader.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_1ODj8s-E01o/SMfMghs6EQI/AAAAAAAAADk/PlnUkqDxiWY/s400/ServerNameHeader.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5244385150270836994" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Particularly with a tool such as FireBug or another DOM inspector, you can get immediate information without having to start any kind of tracking tool or needing to relaunch the site.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-4502135373537879807?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/4502135373537879807/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=4502135373537879807' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/4502135373537879807'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/4502135373537879807'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2008/09/identifying-servers-in-web-farm-with.html' title='Identifying servers in a web farm with IIS headers'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_1ODj8s-E01o/SMfMVN0QdLI/AAAAAAAAADc/d1U9uX1Wd2c/s72-c/ServerNameHeader-IIS.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-1883377691507700717</id><published>2008-09-04T09:10:00.002-04:00</published><updated>2008-09-04T09:17:28.879-04:00</updated><title type='text'>Correction: Chrome does cheque speling</title><content type='html'>I &lt;a href="http://www.compiledthoughts.com/2008/09/google-chrome-shiny-new-and-very-cool.html"&gt;recently posted&lt;/a&gt; about chrome and complained that it doesn't have spell check.  Apparently it does.  But it doesn't seem to work in Blogger.  Odd considering Google owns Blogger.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Spellcheck seems to work in regular textboxes, but Blogger's "compose" view doesn't use that it seems.  I'm not sure &lt;span class="Apple-style-span" style="font-style: italic; "&gt;what&lt;/span&gt; it uses though.  I tried the Chrome page inspector but I can't see what it's doing.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Oh well, I suppose that's part of being beta.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-1883377691507700717?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/1883377691507700717/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=1883377691507700717' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/1883377691507700717'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/1883377691507700717'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2008/09/correction-chrome-does-cheque-speling.html' title='Correction: Chrome does cheque speling'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-53634110902367732</id><published>2008-09-03T09:43:00.004-04:00</published><updated>2008-09-03T10:52:49.441-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='technology'/><category scheme='http://www.blogger.com/atom/ns#' term='development'/><category scheme='http://www.blogger.com/atom/ns#' term='Windows'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Enriching .NET Windows Apps with the WebBrowser control</title><content type='html'>I am currently working on a desktop product upgrade project.  The old versions were developed on the .NET 1.1 platform.  They utilized a web browser control to display information for printing.  Unfortunately the support for hosting a web browser control in a windows form was poor so the original development team had to create their own control with hooks into the Internet Explorer objects and such to do it.  Among other changes, we are doing a complete re-write of this application in .NET 2.0.  (We still need to support some older platforms, so 3.0 wasn't an option.)&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;One of the requirements of the new version dictated that we need to do some more intricate display of the information.  The prime display control candidate for this information is a "tree-grid" hybrid.  The standard .NET 2.0 toolbox simply doesn't have a control that can handle what we need (a shame really).  There are many third party controls that could do this, but that introduced a learning curve that our project timeline simply wouldn't support.  Obviously, there is additional cost involved with such a control as well.  As I evaluated what we needed to achieve, and being a web developer, I naturally looked towards HTML as a solution.  The desired output could be executed very simply with standard HTML constructs.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;While analyzing the current application architecture and scoping out how we were going to integrate the changes, we decided to change the data storage strategy as well.  The application uses a local MS-Access database with a small set of tables to store standard relational data.  Given that we really don't need relational access to the ancillary tables of the data model, we determined that we could simplify the whole thing greatly by reducing the data architecture to a single table with a blob of XML to represent the bulk of the record's detail.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now that we have serialization going on for database storage, the natural step was to use that XML for display.  One of the great additions made in fx 2.0 is the &lt;a href="http://msdn.microsoft.com/en-us/library/system.windows.forms.webbrowser.aspx"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;System.Windows.Forms.WebBrowser&lt;/span&gt; control class&lt;/a&gt;.  This provides simple, native hosting of a web browser inside a windows form.  To solve the complex display problem, we placed a web browser control on the main user control, serialize the data model object instance to XML, apply an XSL transformation to it then feed the result directly to the web browser control in the form.  The browser control has the property "&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;DocumentText&lt;/span&gt;" which you can write HTML directly to.  Elegant, simple and surprisingly fast.  A natural side effect of this strategy is that it becomes trivial to change the view of the data: simply develop a different style sheet and provide a switching mechanism.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;While generating XML, transforming it to HTML and displaying it on the form was now very easy with the browser control, the big question was, how do we interact with it.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;In order for the browser to interact with the user control, it must be exposed to COM by being decorated with the &lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;COMVisibleAttribute&lt;/span&gt; class.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space: pre; "&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new'; "&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new'; "&gt;[ComVisible(true)]&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space: pre; "&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new'; "&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new'; "&gt;public partial class OurUserControl : UserControl&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space: pre; "&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new'; "&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new'; "&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new'; "&gt;&lt;span class="Apple-tab-span" style="white-space: pre; "&gt; &lt;/span&gt;...&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new'; "&gt;&lt;span class="Apple-tab-span" style="white-space: pre; "&gt; &lt;/span&gt;}&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This exposes the object to COM and thus allows the COM based browser to see and interact with it.  Now we need to tell the browser &lt;span class="Apple-style-span" style="font-style: italic;"&gt;what&lt;/span&gt; to interact with.  The browser control has the property "&lt;a href="http://msdn.microsoft.com/en-us/library/system.windows.forms.webbrowser.objectforscripting.aspx"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;ObjectForScripting&lt;/span&gt;&lt;/a&gt;".  You give this property any object in your windows application context.  In our case, when the user control is created, we hand the browser the actual control instance.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;public OurUserControl()&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;InitializeComponent();&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new'; "&gt;  &lt;span class="Apple-style-span" style="white-space: normal; "&gt;webBrowser1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new'; "&gt;.ObjectForScripting = this;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new'; "&gt; &lt;/span&gt;&lt;/span&gt;}&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This exposes the object to the web browser's window as "&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;window.external&lt;/span&gt;".&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In order for the browser context (i.e. the HTML DOM) to call the methods on the win form context scripting object (the windows user control), we need to make some methods visible.  This is simply a matter of making a public method on the object you have exposed to the browser:&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new'; white-space: pre;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;//this is managed code in the win forms application&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;public void DoSomething(args...)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;//do stuff in the windows app here&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;The browser can now call that method by calling the document window's "external" object.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;/* This is "client-side" javascript living&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt; in the HTML sent to the web browser */&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;function doSomething(){&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;window.external.DoSomething();&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now you can call this javascript method as you would in normal HTML.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;When it comes to argument types, there seems to be a certain amount of implicit conversion going on.  In my experiments, I found that a javascript based variable that was typed to a numeric value came into the managed method call as such.  So if you used "&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;parseInt(...)&lt;/span&gt;" in javascript, you should expect that the managed call will receive a proper &lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;System.Int32&lt;/span&gt; as the argument value.  In most cases what I'm dealing with are strings so the argument values slip right through without any fuss.  If the value type doesn't match up, you'll get an exception about it for sure.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The web browser control also allows you to access the browser's DOM.  The &lt;a href="http://msdn.microsoft.com/en-us/library/system.windows.forms.webbrowser.document.aspx"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;Document&lt;/span&gt; property&lt;/a&gt; returns an instance of &lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;HtmlDocument&lt;/span&gt;.  From here you can get at an instance of an HTML control and manipulate the DOM as you see fit from the managed code.  The browser control itself has many &lt;a href="http://msdn.microsoft.com/en-us/library/system.windows.forms.webbrowser_members.aspx"&gt;methods and properties&lt;/a&gt; to direct it as needed.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;All in all, I'm finding the web browser to be a compelling tool for developing richer windows forms applications using my existing web knowledge and without the need for purchasing additional control libraries.  In a very short time, my team has been able to do some very good proof of concept work that is leading into rapid development of something that only a short time ago had me very concerned for the project timeline.  We did some initial tests with a basic prototype on various platforms to ensure we weren't getting into a snag.  The application ran happily on Windows XP, Windows 2000 and Windows Vista.  Those are our target platforms, so I'm pleased with the outcome.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The recent (yesterday) release of Google Chrome suggests that we might one day be able to integrate the open source WebKit rendering engine as an alternative to the embedded Internet Explorer browser control.  Aside from the obvious decoupling of our application from I.E., this could also mean that our application could potentially run on a non-windows .NET platform such as Mono.  However, we'll stick with I.E. and windows for now.  The enhancements we are making with the web browser rendering and .NET 2.0 upgrade are enough for this go around.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-53634110902367732?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/53634110902367732/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=53634110902367732' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/53634110902367732'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/53634110902367732'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2008/09/enriching-net-windows-apps-with.html' title='Enriching .NET Windows Apps with the WebBrowser control'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-8286065872435307627</id><published>2008-09-03T00:27:00.003-04:00</published><updated>2008-09-03T00:41:41.870-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='technology'/><title type='text'>Google Chrome: Shiny, new and very cool</title><content type='html'>I just finished reading the 38 page comic style technical overview book on Chrome.  They implemented some pretty interesting things.  Of definite interest is the process isolation used to separate the tab and plugin processes.  As a GMail user, I notice the performance affects on the other tabs when I'm running GMail.  Also, with the bloated Flash and PDF plugins, it seems that so many page loads just bog everything down.  It will be interesting to see what the performance is like with Chrome.  &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Other particularly interesting features are the "incognito" mode tab that does not log any history and the new-from-scratch javascript engine/virtual machine they are calling V8.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;div&gt;A couple things I've already noticed that I'm a little dissappointed with: There doesn't seem to be an automatic spell check like Mozilla has, and the zoom feature is only a text size changer, not a natural zoom like Opera or the latest Mozilla.  Perhaps they are still working on that.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Despite being currently beta, as are so many of Goggle's applications, it's pretty fair to say that it's still better than many other applications.  Being open source, it will be fun to see all the projects that spin off from the various pieces that make up this new browser.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'm definately going to give Chrome a whirl and see how my web experience changes.  And of course, now I need to test all my web applications to see if they behave!&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-8286065872435307627?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/8286065872435307627/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=8286065872435307627' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/8286065872435307627'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/8286065872435307627'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2008/09/google-chrome-shiny-new-and-very-cool.html' title='Google Chrome: Shiny, new and very cool'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-5161873246353959883</id><published>2008-08-30T07:30:00.004-04:00</published><updated>2008-08-30T10:36:35.887-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='productivity'/><category scheme='http://www.blogger.com/atom/ns#' term='technology'/><category scheme='http://www.blogger.com/atom/ns#' term='hardware'/><title type='text'>MaxiVista as a Keyboard/Mouse switch</title><content type='html'>In order to connect to my workplace VPN, I am required to use my work laptop which has a custom VPN client.  Unfortunately, they don't give us the VPN  client so I'm unable to install it on another machine such as my home computer.  I don't have the extra hardware or space at home to set up a full workstation for the laptop with my preferred keyboard and mouse.   However, I have those set up on my home workstation and a copy of &lt;a href="http://www.maxivista.com/"&gt;MaxiVista&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;MaxiVista is a utility that allows you to use another physical PC connected to your LAN as an additional monitor.  It's not capable of high speed graphics but quite suitable for development.  When you move the mouse pointer across screen boundaries, you switch between your locally attached display and the network attached display.  One of the features of MaxiVista is the ability to switch the remote screen between "additional monitor" mode and "remote control" mode.  This basically allows you to use MaxiVista as an automatic K/M switch, using your primary PC (running the MaxiVista server) as the hardware host for the keyboard and mouse but work on the remote PC desktop.&lt;br /&gt;&lt;br /&gt;So I fire up my laptop, connect to the work VPN, then use the remote control method of MaxiVista on my home workstation to use the better keyboard and mouse on my laptop.  While working, I can instantly move over to my home workstation screens.  This can be particularly helpful when I want to test web applications or .NET remoting scenarios I'm developing on the laptop.  I can jump right to my home environment to test network behavior.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-5161873246353959883?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/5161873246353959883/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=5161873246353959883' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/5161873246353959883'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/5161873246353959883'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2008/08/maxivista-as-keyboardmouse-switch.html' title='MaxiVista as a Keyboard/Mouse switch'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-4112131695167362253</id><published>2008-08-13T08:47:00.003-04:00</published><updated>2008-08-13T09:07:10.751-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='technology'/><category scheme='http://www.blogger.com/atom/ns#' term='IIS'/><category scheme='http://www.blogger.com/atom/ns#' term='Windows'/><category scheme='http://www.blogger.com/atom/ns#' term='networking'/><title type='text'>Serving Neuros OSD Media Files With IIS</title><content type='html'>I &lt;a href="http://www.compiledthoughts.com/2008/07/neuros-osd-wrt160n-dd-wrt-media-center.html"&gt;recently got a Neuros OSD working&lt;/a&gt; on my home network.  It's hooked up to my DVR box.  I DVR programs (mostly for my kid), then use the DVR's "Copy to VCR" feature to dump them to the Neuros and out to my NAS server.  The primary purpose is to archive shows somewhere other than the DVR.  Of course, the handy benefit of being able to watch them on a laptop or make DVDs from them helps too.&lt;br /&gt;&lt;br /&gt;The first problem I encountered was that using the Neuros' default settings for the "TV format" recording left it in a mostly unusable state on my PC.  The video is encoded in &lt;a href="http://en.wikipedia.org/wiki/Mp4"&gt;MP4&lt;/a&gt; while the audio is &lt;a href="http://en.wikipedia.org/wiki/Advanced_Audio_Coding"&gt;AAC&lt;/a&gt;.  It is likely that I just don't have all the right CODECs on my windows machines to run it.  Despite that, I soon discovered that I could change the audio format of the recording.  Switching it to MP3 did the trick.&lt;br /&gt;&lt;br /&gt;I recently came across some segments of a science show that I wanted to share with some friends.  So I recorded them to the NAS.  The NAS share that contains all my media hangs off my server at home so I figured it was fairly trivial to just point my friends at the MP4 file.  This didn't work.  IIS reported a 404 error.&lt;br /&gt;&lt;br /&gt;At first I figured it was a problem with some URL encoding, because the directory and file names had some punctuation and such that I thought might mess it up.  But after cleaning the names to letters only, it still failed.  I then remembered something a co-worker told me about IIS.  Apparently IIS is set up with a list of MIME types and this list determines what it will serve.  MP4 isn't one of them.  I had always assumed that IIS would just serve any file.  Of course, in some cases the file types are mapped to ASAPI filters or application extensions for more advanced handling, such as for PHP or ASP.NET.  But it was a surprise to find that certain types simply wouldn't be served.&lt;br /&gt;&lt;br /&gt;So... I added the MIME type "video/mp4" with the .mp4 extension and I can now at least download the file from the site.  However, it seems that I can't watch it until it's fully downloaded.  Not a major problem, but it would be nice to be able to start watching right away.  Downloading a 10 minute video took about 3.5 minutes, so I should be able to watch it in a streaming fashion.  I imagine this is just an issue with the MP4 format.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-4112131695167362253?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/4112131695167362253/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=4112131695167362253' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/4112131695167362253'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/4112131695167362253'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2008/08/serving-neuros-osd-media-files-with-iis.html' title='Serving Neuros OSD Media Files With IIS'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-7882222936397803095</id><published>2008-08-06T23:12:00.003-04:00</published><updated>2008-08-06T23:20:42.535-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='technology'/><category scheme='http://www.blogger.com/atom/ns#' term='Windows'/><title type='text'>Firefox 3: Down in flames</title><content type='html'>I successfully installed Firefox 3 on WinXPPro-SP2 this evening.  I already had FF2.  Despite a clean install, I was unable to actually launch it.  I got an immediate crash and the subsequent crash detector happily sent my crash report to Mozilla.  After the 3rd time I gave up.&lt;br /&gt;&lt;br /&gt;I uninstalled it and tried again.  No change.  So I downloaded and installed 2.0.0.16 and I'm back up.  I suspect now that the problem might lie with FireBug and its compatibility with FF3.&lt;br /&gt;&lt;br /&gt;All I was really trying to do was reinstall with the DOM inspector so I could look at style sheet behavior.  Fortunately, that is now working.  I was also happy to see that all my settings, customizations and add-ons were seamlessly restored.  Kudos to Mozilla (at least for pre version 3).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-7882222936397803095?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/7882222936397803095/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=7882222936397803095' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/7882222936397803095'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/7882222936397803095'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2008/08/firefox-3-down-in-flames.html' title='Firefox 3: Down in flames'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-2354149532950276348</id><published>2008-07-25T10:02:00.005-04:00</published><updated>2008-12-10T21:01:03.798-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Windows'/><category scheme='http://www.blogger.com/atom/ns#' term='networking'/><title type='text'>Clearing cached passwords in Windows</title><content type='html'>For quite some time I'd struggled with the occasional problem of cached passwords in Windows.  You've probably had this happen before.  You have some network resource such as a file server share that you need to access.  When accessing it you are prompted for Windows credentials.  So you put in a username and password, and because you don't want to go through that process every time, you select "Remember my password".&lt;br /&gt;&lt;br /&gt;But then one day something doesn't work or you simply want to change how you are connecting to that resource.&lt;br /&gt;&lt;br /&gt;I originally thought it might have something to do with the cached network connection itself.  Going into a command prompt and typing "net use" will show you all the network resource connections you've made since the last login/boot.  You can also use "net use" to disconnect them.  However, if you've saved a password for the resource you still won't be prompted for one even on a new connection.&lt;br /&gt;&lt;br /&gt;The question remains: Where exactly do those passwords go??&lt;br /&gt;&lt;br /&gt;Go to Start -&gt; Control Panel -&gt; User Accounts&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_1ODj8s-E01o/SInhUtBlXQI/AAAAAAAAACs/oywPtEBIr1E/s1600-h/UserAccountsAdvanced.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_1ODj8s-E01o/SInhUtBlXQI/AAAAAAAAACs/oywPtEBIr1E/s400/UserAccountsAdvanced.png" alt="" id="BLOGGER_PHOTO_ID_5226956588340043010" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Select the "Manage Passwords" button.  You'll get the "Stored User Names and Passwords" dialog:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_1ODj8s-E01o/SInhh1__bTI/AAAAAAAAAC0/OaFLORR2dy4/s1600-h/StoredCredentials.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://2.bp.blogspot.com/_1ODj8s-E01o/SInhh1__bTI/AAAAAAAAAC0/OaFLORR2dy4/s400/StoredCredentials.png" alt="" id="BLOGGER_PHOTO_ID_5226956814087580978" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This contains Microsoft Passport/Windows Live logins that are associated with the current logged in user profile as well as the saved passwords for network connections.  You can add,  remove or change as you like.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-2354149532950276348?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/2354149532950276348/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=2354149532950276348' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/2354149532950276348'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/2354149532950276348'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2008/07/clearing-cached-passwords-in-windows.html' title='Clearing cached passwords in Windows'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_1ODj8s-E01o/SInhUtBlXQI/AAAAAAAAACs/oywPtEBIr1E/s72-c/UserAccountsAdvanced.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-8462037270866851119</id><published>2008-07-23T08:27:00.002-04:00</published><updated>2008-07-23T08:51:20.548-04:00</updated><title type='text'>Reflection: Personal Uniqueless</title><content type='html'>Yes, the title says &lt;span style="font-style: italic;"&gt;uniqueless&lt;/span&gt;, that being the opposite of &lt;span style="font-style: italic;"&gt;uniqueness&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;A friend of mine uses the the following tagline on his forum posts:&lt;br /&gt;&lt;blockquote style="font-style: italic;"&gt;"Everyone is unique, except for me."&lt;/blockquote&gt;When I was growing up, I was told, "You are special... there's no one else like you."  That was a nice sentiment.  Unfortunately, it's not quite so true.  With a &lt;a href="http://en.wikipedia.org/wiki/World_population"&gt;world population&lt;/a&gt; of nearly 6.7 Billion people, the chances are pretty good that there is someone who's just like me out there, probably even in my own country.  (Given cultural influences, it's probably even more likely.)  They might even look like me! (Scary thought, and my sincerest apologies.)&lt;br /&gt;&lt;br /&gt;Being ensconced firmly in the information society, it's easier more than ever to find people who are like you.  You come up with a great idea, google it, and find people who have already done it.  Most of the good web site URLs are taken.  There's probably someone, somewhere with your name, married to someone with your spouse's name, with the same set of kids.  Statistics dictate that's its more than likely.&lt;br /&gt;&lt;br /&gt;It's sad really.  Growing up as an "individual", thinking your ideas are unique when they most likely aren't.  Is this cynicism or just the acceptance of reality?  Instead of thinking that my ideas are "special" and "one-of-a-kind", I now take them to the internet and see who else has them to learn more.  I get disappointed when I can't find anything, thinking to myself "I must not be looking hard enough, &lt;span style="font-style: italic;"&gt;someone&lt;/span&gt; must have thought of this already."  Or I think that if I can't find anyone else who's thought of this and publicized it, it mustn't be that good of an idea.  It is provoking to think about how information availability can provide and discourage.&lt;br /&gt;&lt;br /&gt;We may look, act and behave differently, but like the Earth, we are all made up mostly of water and ultimately are just 1 single drop in the very large ocean of the human race.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-8462037270866851119?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/8462037270866851119/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=8462037270866851119' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/8462037270866851119'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/8462037270866851119'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2008/07/reflection-personal-uniqueless.html' title='Reflection: Personal Uniqueless'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-3574095948374997683</id><published>2008-07-21T13:01:00.002-04:00</published><updated>2008-07-21T13:31:51.766-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Merits of a System.Collections.Hashtable</title><content type='html'>I was recently working on a very simple data analysis process involving two lists of items.  One is a list of files on disk, another a list of files in a database table.  The work sets were on the order of 85,000 items each.  I needed to simply scan each list to see if each item existed in the other.  I loaded the two lists into a generic string collection (List&lt;string&gt;) and iterated through each one once, looking in the other for the existence of the item (otherList.Contains(item)).  I ran the process and it took a good 2 to 3 minutes to complete.  Reasonable I though, as it was many 10s of thousands. &lt;br /&gt;&lt;br /&gt;I then thought about the way the code was probably running internally.  I imagined that the List&lt;t&gt;.Contains method is probably just doing it's own internal loop and comparing the item against each one in the list until it finds a match.  Otherwise, it runs through to the end.  I remembered that the Hashtable organizes the list of items by the hash of the key so it might have a better and more efficient way of finding items based on that logic.  I refactored the code to use Hashtable instead of the List&lt;string&gt;.  In addition to finding that I had some duplicates in the list coming from the database (fixed after adding a "DISTINCT" to the query) I found that the the process now took about 5 seconds!  That's an insane improvement.  I'm curious how the Hashtable does it's thing.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-3574095948374997683?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/3574095948374997683/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=3574095948374997683' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/3574095948374997683'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/3574095948374997683'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2008/07/merits-of-systemcollectionshashtable.html' title='Merits of a System.Collections.Hashtable'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-1567139664118143671</id><published>2008-07-15T01:00:00.000-04:00</published><updated>2008-07-15T01:01:58.367-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='technology'/><category scheme='http://www.blogger.com/atom/ns#' term='hardware'/><title type='text'>Neuros OSD + WRT160N + DD-WRT = Media center happiness</title><content type='html'>For a while I have had my eyes on the &lt;a href="http://wiki.neurostechnology.com/index.php/Neuros_OSD"&gt;Neuros OSD&lt;/a&gt;: "The Open, Embedded Media Center".  Not long ago, I got one.  I hooked it up to my digital cable DVR and started playing with it.  Unfortunately, I don't have network cabling down to my living room where the entertainment center lives so I was limited to using flash/thumb drives plugged into the front of the OSD.  Having only a couple thumb drives of a few gig, this greatly limited the amount of recording I could do, basically a 30 minute show (at highest video size and quality) per drive.  While experimenting I relied on &lt;a href="http://en.wikipedia.org/wiki/Sneakernet"&gt;sneakernet&lt;/a&gt; to move the recorded shows to my 0.5 Terabyte network attached storage.&lt;br /&gt;&lt;br /&gt;Whether or not to network the OSD wasn't a question, it would be networked.  However, I pondered for a while how I would get it hooked up physically.  Due to the limitations in running a physical cable, I was left with the possibility of setting it up via WIFI.  Understandably, the OSD does not come with WIFI, only a standard 100Mb RJ45 jack for direct connection to an ethernet network.&lt;br /&gt;&lt;br /&gt;So I was off to my local Best Buy to see what they had for wireless devices.  I found a standard Linksys wireless access point whose box hinted at the capability of being a wireless bridge.  60 bucks for a single wire to wireless bridge.  Meh.  For 100 bucks they had a wireless game bridge.  Huh??  How is that any different?  For 70 bucks I could get a whole standard router/gateway/access point.  Despite any marketing-speak suggestion that I might be able to use a standard router as a bridge, I picked the Linksys WRT160N as the hardware for this experiment knowing where I was headed next...&lt;br /&gt;&lt;br /&gt;The factory installed firmware for the WRT160N is not much different than previous versions I've seen in the stock Linksys routers (both wired [BEFSR41] and wifi [WRT54G] versions).  The options are acceptable but not terribly flexible and there doesn't seem to be a way to configure the router as a wifi bridge.  So in comes &lt;a href="http://www.dd-wrt.com/wiki/index.php/Main_Page"&gt;DD-WRT&lt;/a&gt;, an open source wireless router firmware alternative.  I followed the specific instructions for the firmware version for my new router, flashing it with the new DD-WRT version (v24).   I set up the wireless settings to match my network configuration (enabled WEP, entered keys), added the new router's WLAN MAC address to the MAC address restriction list on my existing access point/gateway, and gave the router the right static IP information to put it on the same subnet as the rest of my gear.  After a reboot, I was able to traverse the wireless bridge connection and see network resources on the other side!&lt;br /&gt;&lt;br /&gt;Much of this time during setup I had a laptop hooked up and set with a static IP.  The new router has DHCP disabled so I needed to ensure that I could connect.  To ensure I wasn't getting false positives on my tests I disabled the laptop wireless to ensure everything was going over the wire to the bridge router.  Once it appeared that the bridge was functioning properly, I reverted the laptop network adapter settings back to standard DHCP mode to see if I could pick up an address from the gateway/AP/DHCP server.  Sure enough, it worked!&lt;br /&gt;&lt;br /&gt;At this point I was very delighted that all seemed to be working, however I remained cautiously optimistic, as I still needed to get the OSD wired to it and talking.  (There was a very small glint of skepticism because I bought the OSD off a friend who had had problems getting it connected to his network.)  I moved the router into it's place into the entertainment cabinet and hooked it up to the OSD.  After power cycling both I went to the OSD networking settings screen and instructed it to look for a wireless bridge.  Apparently this is not what I needed, as it failed.  I suspect that this is for a specific wireless connector device.  So instead, I instructed it to configure automatically using DHCP.  Again, despite suspicions that I'd be plagued with problems, it worked!&lt;br /&gt;&lt;br /&gt;After making the decision to try the wireless bridge approach, I was greatly concerned about the amount of network throughput the OSD would need to reliably stream a live recording to a network drive.  I started testing it by playing back some recordings I'd already moved to the NAS box.  These played without difficulty.  Then I set up a recording and let it run.  This didn't seem to have any issues either.  (I didn't watch the entire recording so I can't really say for sure that it completed without a glitch.) &lt;br /&gt;&lt;br /&gt;Later on I discovered the Bandwidth Monitoring tab under the Status tab of the DD-WRT firmware admin site.  This provides a live graph of the WAN, LAN and WLAN network usage in both bits/sec and bytes/sec.  While recording at the highest settings for recording resolution, quality and audio sampling, the OSD appears to only be pushing out about 400 kilobytes per second.  My existing wireless access point is a WRT54G set to wireles-G mode so the new router is limited to that, however, there is still ample bandwidth and throughput available to service the OSD reliably by the looks of it.  I am pleasantly surprised at how well it is all working.  (Of course, something will break tomorrow for sure just to prove me wrong.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-1567139664118143671?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/1567139664118143671/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=1567139664118143671' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/1567139664118143671'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/1567139664118143671'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2008/07/neuros-osd-wrt160n-dd-wrt-media-center.html' title='Neuros OSD + WRT160N + DD-WRT = Media center happiness'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-2324300860870110596</id><published>2008-06-27T08:46:00.002-04:00</published><updated>2008-06-27T08:50:06.208-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='web development'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='ASP.NET'/><title type='text'>ASP.NET tactics: Saving files to network shares</title><content type='html'>Getting a web app to talk to the local file system is hard enough.  Getting it to talk to (and certainly to write files) to a networked system is even more difficult.&lt;br /&gt;&lt;br /&gt;The initial problem is that the security context that the site runs as is a local one.  To complicate things, the security context changes as you progress through the life of an ASP.NET web request.  The IIS service typically runs as "Network Service".  However, you can set a particular site or virtual directory to run under another user.  Furthermore, you can configure ASP.NET to impersonate yet another user.  So it can be very difficult to figure out exactly "who" it is that is doing some action against the file system.&lt;br /&gt;&lt;br /&gt;As I mentioned, the user context for these processes are local ones.  In order to successfully access a network share you'll need to run your site and possibly process(es) as domain accounts in order to get security contexts between machines that will cooperate.  Of course, this then also requires both machines being members of the same or trusted domains.&lt;br /&gt;&lt;br /&gt;One solution may be to create a virtual directory in the site you are trying to do this in.  That virtual directory will point to the network location you wish to save files to.  When you set it up you can specify what user to connect as, and in this case you can specify an external user context, such as a local account from the other machine (MACHINENAME\USER).  This would likely be a bit more secure that modifying the IIS sites or process.  When you save files, you'll just save them to a "local" virtual path such as /mysite/myMappedVirtualDir.&lt;br /&gt;&lt;br /&gt;Unfortunately, setting up things like this typically becomes trial-and-error.  You have to just keep trying different things until it works.  It is understandable that web site technologies adhere to the &lt;a href="http://en.wikipedia.org/wiki/Principle_of_least_privilege"&gt;principle of least privilege&lt;/a&gt;, but it often gets in the way of simply getting things done.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-2324300860870110596?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/2324300860870110596/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=2324300860870110596' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/2324300860870110596'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/2324300860870110596'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2008/06/aspnet-tactics-saving-files-to-network.html' title='ASP.NET tactics: Saving files to network shares'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-4043344280483659514</id><published>2008-06-23T14:40:00.004-04:00</published><updated>2008-12-10T21:01:03.932-05:00</updated><title type='text'>Networking a Windows 98 virtual machine</title><content type='html'>Yes, sadly, I had to create a VirtualPC instance of Windows 98.&lt;br /&gt;&lt;br /&gt;I'm getting into a project for an app that must support Windows 98, if you can believe that.  Fortunately in this day and age I can run 98 through virtualization, and it runs very fast on the modern hardware.&lt;br /&gt;&lt;br /&gt;I installed the OS without incident.  However, TCP/IP networking just didn't seem to want to work.   I didn't get any errors regarding hardware or drivers.  The OS found a network adapter called "Intel 21140 based 10/100 mbps Ethernet Controller" that it liked and had a driver for.  I had everything set properly to work on the network I am on.  It just wouldn't acquire an address.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_1ODj8s-E01o/SF_xspu9o5I/AAAAAAAAACk/tLood85DIkE/s1600-h/Win98VPCNetworkSettings.png"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://1.bp.blogspot.com/_1ODj8s-E01o/SF_xspu9o5I/AAAAAAAAACk/tLood85DIkE/s400/Win98VPCNetworkSettings.png" alt="" id="BLOGGER_PHOTO_ID_5215152642937693074" border="0" /&gt;&lt;/a&gt;I googled a bit and found a forum post that wasn't terribly useful but led me to looking at the Virtual PC settings screen for the virtual machine.  Under the "Networking" setting, you can choose the number of adapters and what each adapter is.  It seems the default is "Nortel IPSECSHM Adapter" which Windows 98 doesn't seem to like much.  &lt;br /&gt;&lt;br /&gt;Another adapter choice was "Intel(R) PRO/1000 PL Network Connection" which is the same name of the adapter on the physical machine (or at least the name that shows in the Virtual PC host OS, Windows XP in my case).   So I switched it to that and started the virtual machine.     Presto Chango!  It started right up and the network adapter got an IP address from the DHCP server.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-4043344280483659514?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/4043344280483659514/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=4043344280483659514' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/4043344280483659514'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/4043344280483659514'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2008/06/networking-windows-98-virtual-machine.html' title='Networking a Windows 98 virtual machine'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_1ODj8s-E01o/SF_xspu9o5I/AAAAAAAAACk/tLood85DIkE/s72-c/Win98VPCNetworkSettings.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-6788823971445608377</id><published>2008-06-06T14:47:00.007-04:00</published><updated>2008-06-06T15:26:00.481-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='productivity'/><category scheme='http://www.blogger.com/atom/ns#' term='development'/><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio'/><title type='text'>Productivity with key cords</title><content type='html'>You can assign keyboard short-cuts to start menu items in Windows.  Visual Studio allows you to map every known command to keyboard shortcuts.  This can be a major help for those programs and commands that you use often.  My philosophy is that the keyboard (and thus the keys) are always in the same place (very helpful when you have multiple monitors and a lot of ground to cover with a mouse cursor).  Even when mousing, my left hand is always on the keyboard so many of my most frequently used shortcuts are left-hand-only.  It's amazing how easy it is and how much time it can save.&lt;br /&gt;&lt;br /&gt;Below are my favorites.  Each is preceded with an indicator of where the shortcut is defined ([W]dows or [V]isual [S]tudio). Some of the Visual Studio cords are more applicable for web application development.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;W: Ctrl-Alt-S&lt;/span&gt;&lt;br /&gt;Launch source control.  (Probably only useful for you if you use a explorer type utility for you particular source control system such as VSS or Vault.)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;W: Ctrl-Alt-Shift-S&lt;/span&gt;&lt;br /&gt;Launch SQL Server management studio.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;W: Ctrl-Alt-D&lt;/span&gt;&lt;br /&gt;Launch Windows command shell.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;W: Ctrl-Alt-Shift-P&lt;/span&gt;&lt;br /&gt;    Launch Windows PowerShell.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;W: Ctrl-Alt-F&lt;/span&gt;&lt;br /&gt;Launch Firefox.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;W: Ctrl-Alt-C&lt;/span&gt;&lt;br /&gt;Launch Beyond Compare, my favorite comparison tool.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;W: Ctrl-Alt-E&lt;/span&gt;&lt;br /&gt; Launch Internet Explorer.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;W: Ctrl-Alt-X&lt;/span&gt;&lt;br /&gt; Launch Microsoft Excel.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;W: Ctrl-Alt-M&lt;/span&gt;&lt;br /&gt;  Launch mail app (Outlook in my case).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;W: Ctrl-Alt-V&lt;/span&gt;&lt;br /&gt;   Launch Visual Studio 2005.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;W: Ctrl-Alt-Shift-V&lt;/span&gt;&lt;br /&gt;    Launch Visual Studio 2008.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;W: Ctrl-Alt-O&lt;/span&gt;&lt;br /&gt;   Launch Opera.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;W: Ctrl-Alt-P&lt;/span&gt;&lt;br /&gt;    Launch PasswordSafe (password management tool).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;VS: Ctrl-Alt-Shift-A&lt;/span&gt;&lt;br /&gt;Attach to processes.  I use this to manually attach to running processes instead of always launching apps using "Run" which starts the browser and attaches to the server and browser.  Usually I just run web apps in an active browser and attach as needed.  9 out of 10 times the problems in the code are obvious and I don't need to actually step through code.  Plus, when you have a web app that loads up session variables, requires logins, etc. it's far easier to just dive into debugging then to have to re-launch and go thru all the steps to reproduce a problem.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;VS: Ctrl-Alt-Shift-D&lt;/span&gt;&lt;br /&gt;Detach from all processes.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;VS: Ctrl-Alt-B&lt;/span&gt;&lt;br /&gt;Build solution&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;VS: F6&lt;br /&gt;&lt;/span&gt;Build the active project.  Very handy for when you are fixing simple compile time errors.  If I have a project with many errors that I'm working on, I will quite often just rebuild with this instead of hunting for the collapsed error list as I work my way through the errors.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;VS: Ctrl-Alt-B (VS default shortcut)&lt;/span&gt;&lt;br /&gt;Build solution&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;VS: Ctrl-Alt-Shift-B&lt;br /&gt;&lt;/span&gt;Re-build solution.  For me, this one does require two hands.  But I use it less often as "Build solution" and my right hand is usually on the keyboard already.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;VS: Ctrl-Alt-Shift-C&lt;br /&gt;&lt;/span&gt;Show differences between working file and source controlled copy. (This VS command only works when the focus is on the solution explorer).  However, that is only a matter of the next shortcut.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;VS: Ctrl-Alt-L&lt;br /&gt;&lt;/span&gt;Move focus to the solution explorer.  You can move back and forth between the solution explorer and the active code editing window with this and ESC.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;VS: Ctrl-Alt-Shift-H&lt;br /&gt;&lt;/span&gt;Show file history in source control.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;VS: Ctrl-Shift-F4&lt;br /&gt;&lt;/span&gt;Close all documents.&lt;br /&gt;&lt;br /&gt;The one catch with using shortcuts is that you have to avoid overlap.  You can't set up a short cut in a particular application that is the same as one used in Windows, as Windows will catch it first.  That's why I have some commands modified with the Shift key, such as the process detach short cut that would otherwise conflict with launching a command shell.&lt;br /&gt;&lt;br /&gt;Aside from these, I also use some of the standard built in Windows short-cuts:&lt;br /&gt;WinKey-E: Windows Explorer&lt;br /&gt;WinKey-R: Start -&gt; Run&lt;br /&gt;WinKey-M: Minimize all windows&lt;br /&gt;Ctrl-Shift-ESC: Task manager&lt;br /&gt;&lt;br /&gt;Overall, once you start using keyboard shortcuts you'll find it far easier and faster to execute tasks.  People often comment on how fast I am when working.  It's not so much that I'm faster than them, I just use the apps and tools in a more efficient way.  We all have enough work to do, there's no reason to make it harder by wasting time hunting for programs and commands that we use all the times.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-6788823971445608377?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/6788823971445608377/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=6788823971445608377' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/6788823971445608377'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/6788823971445608377'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2008/06/productivity-with-key-cords.html' title='Productivity with key cords'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-5977649411335219705</id><published>2008-05-30T09:36:00.003-04:00</published><updated>2008-05-30T10:24:55.067-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='web development'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='ASP.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio'/><title type='text'>Web Site vs. Web Application Project</title><content type='html'>In Visual Studio 2005 and later, there are some significant differences between a "web site" and a "web application project" (WAP).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Project structure&lt;/span&gt;&lt;br /&gt;A web site has no project file.  The "site" is simply the collection of files in the site's directory.  Project/binary references and other configuration settings are stored in the web.config file (poor form in my opinion).&lt;br /&gt;&lt;br /&gt;A web application project does have a project file, it's treated as a class library project.  However, the visual studio template for a WAP provides some additional things such as what types of items are visible in the "Add new item" dialog (i.e. web form, master page, user control, web.config, etc) and configuration of debugging such as the settings for the development web server or IIS.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Codebehind/Codefile attribute&lt;/span&gt;&lt;br /&gt;In a WAP, the markup directive (@Page, @Control, etc.) contains the "Codebehind" attribute.  This is actually meaningless to the ASP.NET runtime, it's a linking attribute used by visual studio to indicate what the code-behind file is for the markup file.&lt;br /&gt;In a site, the "Codefile" attribute is used.  This is similar to the "Src" attribute. (I've experimented with the two and can't find a significant difference between them.)  It tells the ASP.NET runtime what source code file should be compiled together with the markup.  This is what links a markup file to a code behind file in the dynamic architecture of web sites.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Compilation&lt;/span&gt;&lt;br /&gt;In both a site and WAP, the markup (AS?X files) are dynamically compiled.  There is an exception but it's an advanced topic.  All code files (including page code-behind) for a WAP are always pre-compiled.  In a site, nothing is pre compiled.  The ASP.NET runtime will compile everything in the App_Code directory into one DLL and each page will get compiled into its own DLL.  This affects the class scope.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Class scope&lt;/span&gt;&lt;br /&gt;Only code in App_Code is available to all classes in a site (that's where you HAVE to put shared code).  In the WAP - because it's pre-compiled - all page classes live together in the same assembly and can thus see each other.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Namespaces&lt;/span&gt;&lt;br /&gt;Perhaps the largest difference between the two is with the namespaces are constructed.&lt;br /&gt;In a WAP all classes are created by default as members of the root namespace defined in the project (typically the project name).  For example, in a project named "MyProject" the new page "MyPage" will have a fully qualified class name of "MyProject.MyPage".  When you create sub directories in the project, visual studio creates another namespace level for pages created in those directories by default.  So if I create a folder "Admin" and another page "MyPage" I will get a class name of "MyProject.Admin.MyPage". &lt;br /&gt;&lt;br /&gt;In a site, all pages are part of the default root namespace for dynamically compiled pages: "ASP".  Class names are created with underscore separation of their location when they live in sub directories.  In a web site, instead of "MyProject.Admin.MyPage" the page class would actually be "Admin_MyPage".  When it's dynamically compiled it will become "ASP.Admin_MyPage".&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Which to chose&lt;/span&gt;&lt;br /&gt;It is important to chose the right project type.  With the changes introduced in Visual Studio 2005, it is now much easier to work with either type of project (no more IIS integration, woohoo!).  Being able to open a web site via FTP is very helpful for certain needs.  For some, the web site model will be ample.  It's great for tests or simple sites that aren't code intensive.&lt;br /&gt;&lt;br /&gt;However, I have found that in professional development the WAP is the better choice.  Because there is a project file "controlling" the project it's easier to manage it with regards to what is actually included in the project which helps to control things such as the source control repository items for the project.  In my case, having the project file is also necessary for the build system as the project file provides the parameters for what to build for a given project. &lt;br /&gt;&lt;br /&gt;Yes, using a WAP forces us to always precompile the application.  On the down side, this makes updates more difficult because any other changes are rolled in with it, we can't just update one single page.  However, this is good in several ways. &lt;br /&gt;&lt;br /&gt;Simply put, production code should not be updated willy-nilly.  We need to exercise a fair amount of control over what gets pushed to production.  The app should be regression tested by QA.  Also, with a good build system and source control practices, you can do updates as necessary to deploy patches without including changes being made in a given applications main trunk.  If you do need to make a change, there are ways to "patch" a single page by reverting it to the web site code file model.&lt;br /&gt;&lt;br /&gt;Another benefit of using the WAP is that the project configuration is kept in the project file instead of in the web.config, where it really doesn't belong.  This keeps the concerns (configuration of the actual app versus configuration of the project within Visual Studio) well separated.&lt;br /&gt;&lt;br /&gt;Yet another good aspect to the WAP is that you can "see" all the classes in the project - they are all within the scope of the entire assembly.  In some large projects with many developers and many pages that require query string arguments to function I've used a technique for doing "&lt;a href="http://imar.spaanjaars.com/QuickDocId.aspx?quickdoc=371"&gt;strongly typed page urls&lt;/a&gt;".  Follow the link for more details, but in short: I create static page methods that return a properly formed URL.  Using a managed method provides the opportunity to force required page parameters by using regular method arguments.&lt;br /&gt;&lt;br /&gt;This is all obviously very biased towards using the WAP.  This is partially due to where ASP.NET development started, in 1.1, with the web project.  In the interest of full disclosure, I haven't worked with the web site model enough to really speak fairly for it.  However, between the little I've worked with it and from what I've heard from speaking with other developers, for anything that isn't a trivial web site, the WAP is the way to go.  The web site type is good in some cases, but as with any tool, it should be used where appropriate.  Fortunately, Visual Studio has pretty good support for converting a web site to a web application project, so starting upgrading from a site is not terribly difficult.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-5977649411335219705?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/5977649411335219705/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=5977649411335219705' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/5977649411335219705'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/5977649411335219705'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2008/05/web-site-vs-web-application-project.html' title='Web Site vs. Web Application Project'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-6057657939979289883</id><published>2008-05-29T10:20:00.002-04:00</published><updated>2008-05-29T10:23:56.409-04:00</updated><title type='text'>Mobilized Organization</title><content type='html'>LifeHack has a good article on &lt;a href="http://www.lifehack.org/articles/technology/use-mobile-phone-to-stay-organized-on-the-go.html"&gt;staying organized using a mobile phone&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I have started use google calendar in this way a bit.  I'm fortunate in that I have no commute to work and I'm generally either at work or at home so I'm hardly away from a computer.  Plus, I generally don't have that much going on that I need to schedule.  &lt;br /&gt;&lt;br /&gt;Good article though.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-6057657939979289883?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/6057657939979289883/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=6057657939979289883' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/6057657939979289883'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/6057657939979289883'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2008/05/mobilized-organization.html' title='Mobilized Organization'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-8449895497278201153</id><published>2008-05-21T13:56:00.002-04:00</published><updated>2008-05-21T14:01:26.848-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='productivity'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='technology'/><category scheme='http://www.blogger.com/atom/ns#' term='development'/><title type='text'>Continous Monitoring &amp; cool gizmos</title><content type='html'>I just listened to an interesting interview on &lt;a href="http://www.hanselminutes.com"&gt;Hanselminutes&lt;/a&gt; with Owen Rogers, one of the original developers of &lt;a href="http://ccnet.thoughtworks.com/"&gt;CCNet&lt;/a&gt;.  They discussed continuous integration and continuous monitoring.  Well worth a listen.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.hanselminutes.com/default.aspx?showID=131"&gt;Get the show here&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;During the interview Scott and Owen mentioned a few technologies/products I hadn't heard of yet.  One is &lt;a href="http://www.gumstix.com"&gt;Gumstix&lt;/a&gt;, which are super-micro Linux computers, literally the size of a stick of chewing gum.  Another is &lt;a href="http://www.chumby.com"&gt;Chumby&lt;/a&gt; a wifi-connected open Linux platform alarm clock on steroids.  Some very cool stuff that I definitely need to learn more about (and of course will eventually succumb to purchasing).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-8449895497278201153?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/8449895497278201153/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=8449895497278201153' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/8449895497278201153'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/8449895497278201153'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2008/05/continous-monitoring-cool-gizmos.html' title='Continous Monitoring &amp; cool gizmos'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-1289056679887226488</id><published>2008-05-15T01:25:00.006-04:00</published><updated>2008-12-10T21:01:04.299-05:00</updated><title type='text'>Progress - in bytes per second</title><content type='html'>Just over 10 years ago I had a good day connected to the internet.  I was on a dial-up ISP getting a 57,600 bps connection speed.  I was on for nearly 15 hours and received over 151 Megabytes! WOW!  Before I disconnected I took a screen shot for posterity.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_1ODj8s-E01o/SCvKawMxaNI/AAAAAAAAACU/4UfMmreQpxg/s1600-h/tiacgoodday.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_1ODj8s-E01o/SCvKawMxaNI/AAAAAAAAACU/4UfMmreQpxg/s400/tiacgoodday.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5200472755693250770" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I recently downloaded some ISOs of Ubuntu Linux on my broadband cable connection.  The download of about 524 Megabytes took maybe 10 minutes and maxed out at 1,027 KB/sec.  Not to shabby for a sustained speed.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_1ODj8s-E01o/SCvMLgMxaOI/AAAAAAAAACc/IU2My0TkJZ8/s1600-h/AnotherGoodDownloadDay.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_1ODj8s-E01o/SCvMLgMxaOI/AAAAAAAAACc/IU2My0TkJZ8/s400/AnotherGoodDownloadDay.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5200474692723501282" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I just did a &lt;a href="http://www.speedtest.net"&gt;speed test&lt;/a&gt; and got an astounding 9151 kb/sec!  If my math is correct, that's an increase of 9,313,024, or 16,168%!!  I guess I shouldn't expect less from a 10 year gap.  It's just too bad that I can't drive 161 times faster than I did in '98.  (But I think gas prices are trying to keep up!)&lt;br /&gt;&lt;br /&gt;I can't wait until fiber is competitively priced.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-1289056679887226488?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/1289056679887226488/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=1289056679887226488' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/1289056679887226488'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/1289056679887226488'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2008/05/progress-in-bytes-per-second.html' title='Progress - in bytes per second'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_1ODj8s-E01o/SCvKawMxaNI/AAAAAAAAACU/4UfMmreQpxg/s72-c/tiacgoodday.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-5392823736570317717</id><published>2008-05-15T00:59:00.003-04:00</published><updated>2008-05-15T01:24:04.338-04:00</updated><title type='text'>Ubuntu Adventures: WP/mysql/smbfs</title><content type='html'>Captains Log: 14 May 2008&lt;br /&gt;&lt;br /&gt;Tonight I continued my experiments with Linux.&lt;br /&gt;&lt;br /&gt;I managed to install mysql-server although I haven't yet gotten any databases set up yet.  I also installed WordPress but also don't have that running yet.&lt;br /&gt;&lt;br /&gt;The bigger achievement was getting the Linux box to see the file shares on my HP MediaVault NAS box.  I found &lt;a href="http://h10025.www1.hp.com/ewfrf/wc/document?docname=c00792602&amp;lc=en&amp;cc=us&amp;dlc=&amp;product=3193058"&gt;the HP instructions&lt;/a&gt; for doing this and had a go.  I tried mounting it using NFS but it didn't seem to want to do anything.  So I ended up installing Samba ("apt-get install smbfs").  Then I was able to mount using smb.  After finding instructions on &lt;a href="http://esthermofet.blogspot.com/2007/09/accessing-hp-mediavault-2010-20x0.html"&gt;how to set up the credentials&lt;/a&gt; bit of it, I was able to configure the /etc/fstab file to provide automatic mounting of the NAS shares.  Very cool.  &lt;br /&gt;&lt;br /&gt;In retrospect, I think NFS might work. I realized after smb failed the first time that the NetBios name of the box was resolving.  I did a quick ping test, and saw a reply but I didn't even look at the reply details long enough to realize what happened.  My ISP has recently started replying to all unresolved DNS names with some crummy parking page on their servers.  It's screwed me up more than once.  Some of my machine names don't resolve like they used to.&lt;br /&gt;&lt;br /&gt;One of my secondary goals (if possible) is to be able to put the subversion repositories on the NAS box instead of on the linux server itself so I have some level of hardware redundancy (the NAS is set up with a mirrored volume set at the moment).  I think that by default subversion uses Berkeley DB as the repository data store but you can change that to use just the file system.  If BDB can't be used over a smbfs (which I suspect it can't) then I'll try a file system based repository which hopefully will work.  If neither work, then I guess I'll just have to create a cron job (another learning curve) to regularly backup the repo data stores to the NAS.&lt;br /&gt;&lt;br /&gt;One step at a time.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-5392823736570317717?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/5392823736570317717/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=5392823736570317717' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/5392823736570317717'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/5392823736570317717'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2008/05/ubuntu-adventures-wpmysqlsmbfs.html' title='Ubuntu Adventures: WP/mysql/smbfs'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-7818759749637765080</id><published>2008-05-15T00:21:00.006-04:00</published><updated>2008-05-15T00:58:22.772-04:00</updated><title type='text'>Ubuntu Adventures: The beginning</title><content type='html'>Captain's Log: 5 May 2008&lt;br /&gt;&lt;br /&gt;Mission: Install linux (yet again) and find an actual use for it.  I've installed it several times before, but after finishing, just stared at the login prompt and thought to myself, "Well, now what do I do with it?"  This time, I have some goals in mind:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Convert my source control system to subversion (I've tried subversion on WAMP on Windows Server 2003, but it hasn't worked yet.  Good excuse to upgrade to Linux.)&lt;/li&gt;&lt;li&gt;Move my blog from blogger to my own server using WordPress.&lt;/li&gt;&lt;li&gt;Be able to actually claim to have some minuscule clue about a non-Microsoft OS.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Hardware:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Old Compaq desktop&lt;/li&gt;&lt;li&gt;Intel Celeron 500MHz&lt;/li&gt;&lt;li&gt;128MB RAM&lt;/li&gt;&lt;li&gt;250GB HD&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;I have another box (Pentium 4 - 550MHz; 384MB RAM) that is currently running Windows Server.  It is currently hosting FTP and my current source repository (SourceGear Vault).  However, if I can find success with subversion on the Linux installation then I may decommission Windows and switch that box over to a fresh Linux set.&lt;br /&gt;&lt;br /&gt;I installed Ubuntu Linux server.  I attempted to install 8.04 first but it failed for unknown reasons.  However, 6.10 (Edgy Eft) succeeded.  During the installation I am pretty sure I selected the LAMP installation option.  But to be honest I might have done it wrong - I did it during a fly-by while chasing down my 2 year old.  Perhaps I didn't select the right option.  Anyway, after installation I found that neither apache, mysql nor php were installed (at least I got the L part of it working).&lt;br /&gt;&lt;br /&gt;After doing some searching I discovered the apt-get command.  I ran it with some upgrade steps and it updated several packages and modules.  I then used it to install apache and php.  Later I tried "apt-get install subversion" and it worked.  I'm starting to like this!&lt;br /&gt;&lt;br /&gt;Once subversion was installed I created a repository, then started playing with TortoiseSVN from my Windows desktop to put in my whole source tree.  I'll likely blow away the whole repository once I figure out what I'm doing but I'm making progress.&lt;br /&gt;&lt;br /&gt;It's taking some time getting used to the different style of system administration.   I'm so used to all the windows GUI tools for changing settings.   However, I'm really liking the transparency and plain text methodologies of Linux.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-7818759749637765080?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/7818759749637765080/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=7818759749637765080' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/7818759749637765080'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/7818759749637765080'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2008/05/ubuntu-adventures-beginning.html' title='Ubuntu Adventures: The beginning'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-975160217415502147</id><published>2008-05-09T15:28:00.003-04:00</published><updated>2008-05-09T15:59:49.697-04:00</updated><title type='text'>Wait, Wait... Busted</title><content type='html'>My wife and I attended a live performance of the NPR program Wait Wait... Don't Tell Me.  It was very entertaining.  The panelists were Charlie Pierce, Amy Dickinson and Mo Rocca.  The scheduled local guest was planned as Governor Elliot Spitzer, however, as host Peter Sagal said "Some came up. (Then the governor paid $4000 and it went down again.)"  I'll leave it there.  In former governor's place was a large arrangement of flowers.&lt;br /&gt;&lt;br /&gt;To my delight, the replacement guest was television celebrigeek Adam Savage from Discovery channel's MythBusters!  He connected in from a studio in California and was interviewed for a good 20 minutes.  It would have been far cooler to have him there, but it was fun regardless.&lt;br /&gt;&lt;br /&gt;Having worked in radio for many years I am always interested to watch radio show production.  This performance was no exception.  They have call in contestants, a few sound effects and quick thinking participants that the producers and engineers have to work around.  After the show completed they spend 10 minutes and went back through the show doing some re-do takes where they needed to clean up introductions or whatever.  Having a large (~2600 people) live audience complicates it a bit as well.&lt;br /&gt;&lt;br /&gt;Overall, it was a good time and a chance to get out the house.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-975160217415502147?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/975160217415502147/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=975160217415502147' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/975160217415502147'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/975160217415502147'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2008/05/wait-wait-busted.html' title='Wait, Wait... Busted'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-4814619718160047308</id><published>2008-05-03T14:37:00.002-04:00</published><updated>2008-05-03T15:36:27.594-04:00</updated><title type='text'>Finding myself</title><content type='html'>I've struggled for many years finding and/or creating a digital identity for myself.  I've never had a catchy screen name or hacker name or handle or whatever you want to call it.  I'm not creative in that way.  The creativity I do posses is with solving tangible problems in both tactile and abstract domains.  I enjoy handyman type work, do woodworking as a hobby and of course, I work as a software developer so I'm constantly coming up with solutions to technology challenges.  But I'm simply no good at coming up with things out of thin air.  That's why I don't dance, draw or partake in other activities that I'd generally classify as visual art.  It usually requires some form of inspiration from a greater force which I lack.  My inspiration comes from the problems that need to be solved.  (I suppose this is probably true for most technologists.)&lt;br /&gt;&lt;br /&gt;So anyway, I've found it rather difficult to come up with a name to use for my internet presence or for this blog.  Once, my sister said "You're the biggest geek dork I know."  So, still lacking a name different than that given to me while still tethered to my mother's womb, I went and registered geekdork.com.  This certainly fits my general self classification as a geek and dork but it just feels a tad too sophomoric.  I've tried a few names similar to those I've seen on other's blogs, but I hate the feeling of being a sheep just following the shepherds .  But like I have stressed, I just don't have what it takes to make up something good.&lt;br /&gt;&lt;br /&gt;Despite all this, for some reason, yesterday the phrase "compiled thoughts" popped into my head.  It sounded like a good blog title and certainly reflects the whole notion of today's trend of aggregating ones mental randomness and uploading it to the likes of blogs, twitter, or what-have-you.  I did some googling and found very little use of those words together outside of discussions on writing.  I figured that the domain name "compiledthoughts.com" must be taken, but to my surprise, it was not so I grabbed it.  &lt;br /&gt;&lt;br /&gt;I've pointed the domain at this blog for now and renamed it accordingly.  However, I still don't have a "name" for myself, per se.  At this point I guess I'll just keep using my real name, it's boring but easy to remember.  At least now I have a title for the blog that I actually like.  Plus, it sounds mildly intellectual.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-4814619718160047308?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/4814619718160047308/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=4814619718160047308' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/4814619718160047308'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/4814619718160047308'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2008/05/finding-myself.html' title='Finding myself'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-6036179817771112220</id><published>2008-05-03T14:21:00.003-04:00</published><updated>2008-05-03T14:36:42.776-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='development'/><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><category scheme='http://www.blogger.com/atom/ns#' term='csharp'/><title type='text'>Downloading from the series of tubes</title><content type='html'>Yesterday I was working on an automation process to deal with some vendor data.  Unfortunately, the vendor doesn't have the data on an FTP location and names the files with dates so they change whenever updated.  The files have to be downloaded manually from the vendor's web site after logging in.  Not a process that's terribly easy to perform automatically.&lt;br /&gt;&lt;br /&gt;One of my coworkers had already written the bulk of the screen scraping logic that logs in and looks at the download page for the links to the file names of the available downloads.  This works great.  He had put in the code to actually download the file using the HttpWebRequest, HttpWebResponse and byte stream classes.  I commenced some testing and found that only a portion of the data was getting downloaded, leaving the file (a Zip in this case) corrupt.  I googled a bit and found some articles with various suggestions on how to process the response stream from the web response class.  It seems most people had problems with this seemingly simple task.  Then I ran across a suggestion to use the WebClient.GetData() method.  It was only about four lines of code.&lt;br /&gt;&lt;br /&gt;As I pasted it into the program I decided to check out this class I had yet to use, WebClient.  Low and behold, there was also a method called DownloadFile().  What started as a dozen lines of code for manipulating a byte stream that ultimately never even worked was now reduced to a single call:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;   new WebClient().DownloadFile(downloadFileUrl, downloadPath);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;It's always a great feeling when you discover a class you didn't even know existed in the .NET framework that provides exactly what you are looking for.  I'm happy to know that I don't need to become an expert at handling byte streams, instead I can focus on the business problem that I was trying to solve.&lt;br /&gt;&lt;br /&gt;However, it leaves me to wonder endlessly about how many classes or methods I still don't know about that might allow me to reduce the code I write and solve problems in a much cleaning and robust way.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-6036179817771112220?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/6036179817771112220/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=6036179817771112220' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/6036179817771112220'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/6036179817771112220'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2008/05/downloading-from-series-of-tubes.html' title='Downloading from the series of tubes'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-8588785423054921144</id><published>2008-05-01T15:26:00.005-04:00</published><updated>2008-12-10T21:01:04.455-05:00</updated><title type='text'>Beware of non-specific references</title><content type='html'>I recently completed a change to a web application that utilizes the ASP.NET AJAX web extensions (System.Web.Extensions.dll).  This assembly is loaded into the Global Assembly Cache (GAC) and referenced to there by the web project.  I ran the web app locally without any issues.  After updating the source code repository with my changes, I asked the build server to create a new release candidate of the app.  This worked fine.&lt;br /&gt;&lt;br /&gt;I then deployed it to the staging/test server and hit the URL.  Failure!  The error I received was&lt;br /&gt;&lt;br /&gt;"&lt;span style="font-family:Arial,Helvetica,Geneva,SunSans-Regular,sans-serif;"&gt;&lt;b&gt;Parser Error Message: &lt;/b&gt;The base class includes the field 'UpdatePanel1', but its type (System.Web.UI.UpdatePanel) is not compatible with the type of control (System.Web.UI.UpdatePanel).&lt;/span&gt;"&lt;br /&gt;&lt;br /&gt;Clearly, a &lt;span style="font-family:Arial,Helvetica,Geneva,SunSans-Regular,sans-serif;"&gt;System.Web.UI.UpdatePanel &lt;/span&gt;is a &lt;span style="font-family:Arial,Helvetica,Geneva,SunSans-Regular,sans-serif;"&gt;System.Web.UI.UpdatePanel&lt;/span&gt;.  So I investigated further.  My web.config file contained this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;   &amp;lt;compilation defaultLanguage="c#" debug="true"&amp;gt;&lt;br /&gt;     &amp;lt;assemblies&amp;gt;&lt;br /&gt;        &amp;lt;add assembly="System.Web.Extensions, Version=1.0.61025.0, &lt;br /&gt;           Culture=neutral, PublicKeyToken=31BF3856AD364E35"/&amp;gt;&lt;br /&gt;     &amp;lt;/assemblies&amp;gt;&lt;br /&gt;   &amp;lt;/compilation&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This provides the assembly version the web app is loading for the creation of the dynamically compiled pages.  Thus, the update panel created from the markup is the one from the version 1.0.61025.0 assembly.&lt;br /&gt;&lt;br /&gt;I started looking at the web application assembly.  Using BeyondCompare with a conversion rule to process .DLLs with ILDASM I was able to look at the compiled assembly references.  I found my version of the assembly to have the reference as&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;.assembly extern System.Web.Extensions&lt;br /&gt;{&lt;br /&gt;  .publickeytoken = (31 BF 38 56 AD 36 4E 35 ) // 1.8V.6N5&lt;br /&gt;  .ver 1:0:61025:0&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;while the build server's version had&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;.assembly extern System.Web.Extensions&lt;br /&gt;{&lt;br /&gt;  .publickeytoken = (31 BF 38 56 AD 36 4E 35 ) // 1.8V.6N5&lt;br /&gt;  .ver 3:5:0:0&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;So, the code behind instance of the update panel in the prebuilt web app assembly is from the referenced 3.5.0.0 assembly while the runtime instance from the markup is the other version.  This was the culprit. &lt;br /&gt;&lt;br /&gt;This happened because Visual Studio created the reference to the assembly that is in the GAC but created it with the "Specific Version" flag set to "false".   When the project was built on the build server it took the newer assembly for the reference.  I changed the flag to "true" in the project.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_1ODj8s-E01o/SBodwcYfALI/AAAAAAAAACE/Is_gr5B-YyY/s1600-h/WebExtensionsSpecificVersion.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_1ODj8s-E01o/SBodwcYfALI/AAAAAAAAACE/Is_gr5B-YyY/s400/WebExtensionsSpecificVersion.png" alt="" id="BLOGGER_PHOTO_ID_5195497838215102642" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;After committing the change I asked for another build.  Now the build server built assembly had the correct version referenced and the app runs.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-8588785423054921144?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/8588785423054921144/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=8588785423054921144' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/8588785423054921144'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/8588785423054921144'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2008/05/beware-of-non-specific-references.html' title='Beware of non-specific references'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_1ODj8s-E01o/SBodwcYfALI/AAAAAAAAACE/Is_gr5B-YyY/s72-c/WebExtensionsSpecificVersion.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-5572981392113386218</id><published>2008-04-17T01:23:00.002-04:00</published><updated>2008-04-17T01:32:53.801-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='technology'/><category scheme='http://www.blogger.com/atom/ns#' term='hardware'/><title type='text'>MediaVault Mirror Added | deddA rorriM tluaVaideM</title><content type='html'>Monday night I ordered a second drive from NewEgg to match the one already in my HP MediaVault.  It came on Wednesday (way fast delivery!) and I installed it into the box.  &lt;br /&gt;&lt;br /&gt;After a little fighting with the administration tool, I finally got it set up as a mirror.  I tried several times and kept getting either no response (either the page timed out or it just returned me back to the disk settings screen) or I'd get an error.  I couldn't figure out what on earth was wrong.  It is a brand new drive, shouldn't have anything on it.  I didn't format it as the mirror is a block-by-block feature so it shouldn't require an pre-formatting.  What finally worked was that I selected the new disk and chose "Erase Disk".  The erase process only took seconds but I noticed a change in the recognized drive space.  I then tried the mirror process again and it worked right away.  None of the half dozen sets of instructions I read mentioned anything about erasing the drive first, but that is what seemed to be needed.&lt;br /&gt;&lt;br /&gt;So now the main disk volume is in the rebuilding phase and should be done in some 12 hours.  I feel better at least having a mirror of the data.  The next step is to get a removable backup system in place.  Fortunately, the MediaVault has USB ports to which you can connect mass storage devices.  So I just need to get a USB hard drive or similar so I can back up periodically and safely store away.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-5572981392113386218?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/5572981392113386218/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=5572981392113386218' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/5572981392113386218'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/5572981392113386218'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2008/04/mediavault-mirror-added-dedda-rorrim.html' title='MediaVault Mirror Added | deddA rorriM tluaVaideM'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-2167985607181761198</id><published>2008-04-17T01:01:00.006-04:00</published><updated>2008-04-17T01:23:11.276-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='web development'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='ASP.NET'/><title type='text'>Semi-re-written URLs and the ~ resolver</title><content type='html'>I decided to try out using the &lt;a href="http://msdn2.microsoft.com/en-us/library/system.web.httprequest.pathinfo.aspx"&gt;PathInfo property&lt;/a&gt; of the &lt;a href="http://msdn2.microsoft.com/en-us/library/system.web.httprequest.aspx"&gt;HttpRequest class&lt;/a&gt;.  Instead of the typical use of querystring vars &lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    showthing.aspx?thingID=123&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I thought I'd try out creating a friendlier URL such as &lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    showthing.aspx/123&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Instead of using the querystring to get the keyed values, I'd use the PathInfo collection instead.  This in itself worked fine, however a small problem arises. &lt;br /&gt;&lt;br /&gt;The app uses master pages and thus does some URL resolution for resources such as the CSS file.  I've noticed over the years that sometimes the path will resolve to a root relative path:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    /mysite/include/styles.css&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;and sometimes to a relative path:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    ../include/styles.css&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I haven't found any way to control this behavior and I've wondered what determines it.  Today I wondered if it might actually be somewhat sensible in that it will be resolved to the smallest result.  For example if the resource is only 1 directory off, it might be resolved to a back reference (../???) whereas if it's a long was off (perhaps several directories back up) it will resolve to the root (/mysite/???).  There doesn't seem to be a rhyme or reason to it.&lt;br /&gt;&lt;br /&gt;The end result is that when I browse to my semi-re-written URL using path info data, the browser doesn't care that it's path info, so my CSS file reference ends up being something logically like this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;   showthing.aspx/123/../include/styles.css&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;which resolves to&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;   showthing.aspx/include/styles.css&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;which clearly isn't what I've intended.&lt;br /&gt;&lt;br /&gt;If I can determine how to force the ~ resolution behavior to be root relative, then it will fix the problem.  Otherwise, I can't use PathInfo and similarly I can't do any other kind of URL re-writing.   :-(  I suppose I could just make all my resource references root relative, but then I have to significantly change my development strategies.  I tend to favor running in IIS (using virtual directories) for 2 reasons: 1) It's more realistic; 2) I work on some apps that consume web resources from other sites that I also run on my dev machine in IIS which is simpler than dealing with starting and managing 2 instances of Cassini.&lt;br /&gt;&lt;br /&gt;Hopefully there's a way to force the behavior, otherwise it's back to query string vars.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-2167985607181761198?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/2167985607181761198/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=2167985607181761198' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/2167985607181761198'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/2167985607181761198'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2008/04/semi-re-written-urls-and-resolver.html' title='Semi-re-written URLs and the ~ resolver'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-4184144111615315773</id><published>2008-04-14T23:52:00.003-04:00</published><updated>2008-04-15T00:18:18.482-04:00</updated><title type='text'>Super Dead-End?</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://artfiles.art.com/images/-/James-Lemass/Road-Sign-Dead-End-Photographic-Print-C12196565.jpeg"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 400px;" src="http://artfiles.art.com/images/-/James-Lemass/Road-Sign-Dead-End-Photographic-Print-C12196565.jpeg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;What happened to the information super-highway?&lt;br /&gt;&lt;br /&gt;Back in the "old days" (maybe nearly 5 years ago) we used to hear all this talk of the &lt;span style="font-style: italic;"&gt;information super-highway&lt;/span&gt;.  I haven't heard that in a while.  I've heard about social networking/computing, semantic web, and of course the über web 2.0.  Sites with useful or nifty services (google, flickr, del.icio.us, wikipedia) or those with viral penetration (myspace, facebook, youtube) have become parts of our new lexicon. &lt;br /&gt;&lt;br /&gt;But what's happened to the highway?  Are we on it?  Have we surpassed it?  Has information technology graduated up to flying cars and sky-ways and left the super-highway asphalt old and cracked far below, metaphorically speaking?  We just never hear anyone talk about it any more.   I miss the old highway.&lt;br /&gt;&lt;br /&gt;Maybe I'll dust off my old US Robotics 28.8 Kbaud modem and see if I can remember what the old ride used to feel like.  Although, I don't think it will feel quite the same over my VOIP based phone service carried on a 6.5 megabit cable line.  And does windows Vista even support the serial port?&lt;br /&gt;&lt;br /&gt;You can never &lt;span style="font-style: italic;"&gt;really&lt;/span&gt; go home again.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-4184144111615315773?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/4184144111615315773/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=4184144111615315773' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/4184144111615315773'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/4184144111615315773'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2008/04/super-dead-end.html' title='Super Dead-End?'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-1383940952744884656</id><published>2008-04-11T07:57:00.002-04:00</published><updated>2008-04-11T08:22:56.825-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='development'/><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio'/><title type='text'>Microsoft.VSS.Dispose()</title><content type='html'>Yesterday at work, for the first time in 8 years of using Visual Source Safe, I was confronted with the real prospect of having to attempt to branch a set of Visual Studio .NET projects.  Up until now, I have managed to avoid the need, I'm not sure how.&lt;br /&gt;&lt;br /&gt;After some lengthy discussions with the development team, I created a Sandbox VSS database and imported a set of VS2005 projects that make of a single solution.  I created a VSS directory to contain branches, set up the hierarchy and executed a "Share and Branch" operation for each project in the solution into the branch directory.  This worked fine. &lt;br /&gt;&lt;br /&gt;We then started looking at the merge functionality.  I knew all of this existed but had never used it except for once many years ago when the team I was on tried using the "multiple checkout" mode of VSS (we switched back to exclusive checkout not long after).  Our main discovery was that you must merge every file individually.  This isn't to say that you have to merge them &lt;i&gt;manually&lt;/i&gt; however.  While we didn't encounter it this time in the test, my recollection is that VSS will merge automatically unless there is a conflict, then you get the diff/merge dialog to decide what goes.  The important point is that there doesn't seem to be a way to merge an entire VSS directory back to it's initial branch in the tree (lacking the "trunk" terminology in VSS).  You must initiate &lt;i&gt;each&lt;/i&gt; merge operation on &lt;span style="font-style: italic;"&gt;each&lt;/span&gt; file manually.  With 10s of projects in a solution, dozens of changed files and 100s of coexisting files, it is not viable to manually merge every file.  It would be faster to use Floppy/Sneaker Net.&lt;br /&gt;&lt;br /&gt;So I'm becoming more and more convinced that we are closing in on the end of VSS in our organization.  I've been using SVN (Tortoise &amp;amp; Ankh) a bit lately and it seems to work pretty well.  SVN certainly has far better branching support.&lt;br /&gt;&lt;br /&gt;One of my concerns with any SCM system is how to execute branches within the context of visual studio solutions.  If I branch one or more projects then the solution file will need to change, or more practically we'll just create another one for the branch.  But then the project files change as well as the physical location of projects change which needs to be reflected in the project references.  Then, after completing work on a branch when a project file is merged back into the trunk you have to take care to merge project references back to their proper state.&lt;br /&gt;&lt;br /&gt;In addition to all of this, the build system we have been using may encounter issues because of the way the build is executed.  However, if the branched project files are committed correctly then it should behave correctly.&lt;br /&gt;&lt;br /&gt;I think I need to do some extensive reading on:&lt;br /&gt;A) How branching and merging works best for people&lt;br /&gt;B) How to work with Visual Studio using branched projects&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-1383940952744884656?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/1383940952744884656/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=1383940952744884656' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/1383940952744884656'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/1383940952744884656'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2008/04/microsoftvssdispose.html' title='Microsoft.VSS.Dispose()'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-6392755080631485674</id><published>2008-03-31T16:32:00.005-04:00</published><updated>2008-03-31T16:48:36.810-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='development'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio'/><title type='text'>VS Snippet: On-demand getter</title><content type='html'>I often use base page classes in my web apps.  On these classes I put read-only properties for access to business layer classes.  I typically set these getters up to do on-demand (or "lazy" instantiation) because not all pages will use the various business class instances that are available.  Instead of creating them all on class construction or page load, the get created as needed.  After figuring out how to fix the "prop" shortcut to work the way I needed, I realized it made sense to create a snippet for on-demand properties.  Now I simply type "propod" and I get this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; private object myVar;&lt;br /&gt;&lt;br /&gt; public object MyProperty&lt;br /&gt; {&lt;br /&gt;  get&lt;br /&gt;  {&lt;br /&gt;   if(myVar == null)&lt;br /&gt;   {&lt;br /&gt;    myVar = new object();&lt;br /&gt;   }&lt;br /&gt;   return myVar;&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Here's a Visual Studio shortcut snippet file XML for it.  Just save it to a .snippet file in your visual studio snippets directory (i.e. C:\Program Files\Microsoft Visual Studio 9.0\VC#\Snippets\1033\Visual C#):&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;utf-8&amp;quot; ?&amp;gt;&lt;br /&gt;&amp;lt;CodeSnippets  xmlns=&amp;quot;http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet&amp;quot;&amp;gt;&lt;br /&gt;  &amp;lt;CodeSnippet Format=&amp;quot;1.0.0&amp;quot;&amp;gt;&lt;br /&gt;    &amp;lt;Header&amp;gt;&lt;br /&gt;      &amp;lt;Title&amp;gt;propod&amp;lt;/Title&amp;gt;&lt;br /&gt;      &amp;lt;Shortcut&amp;gt;propod&amp;lt;/Shortcut&amp;gt;&lt;br /&gt;      &amp;lt;Description&amp;gt;Code snippet for on-demand read-only &lt;br /&gt;     property and backing field.&amp;lt;/Description&amp;gt;&lt;br /&gt;      &amp;lt;Author&amp;gt;Peter Lanoie&amp;lt;/Author&amp;gt;&lt;br /&gt;      &amp;lt;SnippetTypes&amp;gt;&lt;br /&gt;        &amp;lt;SnippetType&amp;gt;Expansion&amp;lt;/SnippetType&amp;gt;&lt;br /&gt;      &amp;lt;/SnippetTypes&amp;gt;&lt;br /&gt;    &amp;lt;/Header&amp;gt;&lt;br /&gt;    &amp;lt;Snippet&amp;gt;&lt;br /&gt;      &amp;lt;Declarations&amp;gt;&lt;br /&gt;        &amp;lt;Literal&amp;gt;&lt;br /&gt;          &amp;lt;ID&amp;gt;type&amp;lt;/ID&amp;gt;&lt;br /&gt;          &amp;lt;ToolTip&amp;gt;Property type&amp;lt;/ToolTip&amp;gt;&lt;br /&gt;          &amp;lt;Default&amp;gt;object&amp;lt;/Default&amp;gt;&lt;br /&gt;        &amp;lt;/Literal&amp;gt;&lt;br /&gt;        &amp;lt;Literal&amp;gt;&lt;br /&gt;          &amp;lt;ID&amp;gt;property&amp;lt;/ID&amp;gt;&lt;br /&gt;          &amp;lt;ToolTip&amp;gt;Property name&amp;lt;/ToolTip&amp;gt;&lt;br /&gt;          &amp;lt;Default&amp;gt;MyProperty&amp;lt;/Default&amp;gt;&lt;br /&gt;        &amp;lt;/Literal&amp;gt;&lt;br /&gt;        &amp;lt;Literal&amp;gt;&lt;br /&gt;          &amp;lt;ID&amp;gt;field&amp;lt;/ID&amp;gt;&lt;br /&gt;          &amp;lt;ToolTip&amp;gt;The variable backing this property&amp;lt;/ToolTip&amp;gt;&lt;br /&gt;          &amp;lt;Default&amp;gt;myVar&amp;lt;/Default&amp;gt;&lt;br /&gt;        &amp;lt;/Literal&amp;gt;&lt;br /&gt;      &amp;lt;/Declarations&amp;gt;&lt;br /&gt;      &amp;lt;Code Language=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;        &amp;lt;![CDATA[private $type$ $field$;&lt;br /&gt;&lt;br /&gt;public $type$ $property$&lt;br /&gt;{&lt;br /&gt;  get&lt;br /&gt;  {&lt;br /&gt;    if($field$ == null)&lt;br /&gt;    {&lt;br /&gt;      $field$ = new $type$();&lt;br /&gt;    }&lt;br /&gt;    return $field$;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;$end$]]&amp;gt;&lt;br /&gt;      &amp;lt;/Code&amp;gt;&lt;br /&gt;    &amp;lt;/Snippet&amp;gt;&lt;br /&gt;  &amp;lt;/CodeSnippet&amp;gt;&lt;br /&gt;&amp;lt;/CodeSnippets&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-6392755080631485674?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/6392755080631485674/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=6392755080631485674' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/6392755080631485674'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/6392755080631485674'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2008/03/vs-snippet-on-demand-getter.html' title='VS Snippet: On-demand getter'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-746979058869747733</id><published>2008-03-31T15:33:00.004-04:00</published><updated>2008-03-31T16:31:19.217-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='development'/><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio'/><category scheme='http://www.blogger.com/atom/ns#' term='csharp'/><title type='text'>C# "prop" shortcut in Visual Studio 2008</title><content type='html'>Anyone who builds classes in Visual Studio hopefully uses the "prop" shortcut to generate a property with its backing variable.  Just type "prop" and hit tab twice and you get this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; private int myVar;&lt;br /&gt;&lt;br /&gt; public int MyProperty&lt;br /&gt; {&lt;br /&gt;  get { return myVar; }&lt;br /&gt;  set { myVar = value; }&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Update the fields and away you go.  This is a major time saver.  I was disappointed to see Microsoft change its behavior in the 2008 upgrade.  The new behavior is to generate an automatic property:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; public int MyProperty { get; set; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I learned recently where these shortcuts, or snippets are stored.  It turns out it's pretty easy to modify or add to them.  In Visual Studio 2005, you can find them here:&lt;br /&gt;&lt;br /&gt;C:\Program Files\Microsoft Visual Studio 8\VC#\Snippets\1033\Visual C#&lt;br /&gt;&lt;br /&gt;For 2008, here:&lt;br /&gt;&lt;br /&gt;C:\Program Files\Microsoft Visual Studio 9.0\VC#\Snippets\1033\Visual C#&lt;br /&gt;&lt;br /&gt;It appears that there aren't that many changes between versions.  Of course, the one they changed is the one I suspect most of us use the most often.  Shame on them.&lt;br /&gt;&lt;br /&gt;I'm not here to argue the merits of full vs. automatic properties.  I'm all for automatic properties.  The problem happens when we return from VS2008 "Hello World" example to our real world code base.  VS2008 happily upgrades an assembly I created in VS2005 but keeps it backward compatible.  However, it seems that it is not smart enough to recognize that this assembly is targeting the 2.0 framework or rather that the project will still be used in VS2005.  (I suppose one might argue "how would it know?")  All those automatic properties won't compile in the 2.0 compiler while the 3.0+ compilers expand them out automatically.&lt;br /&gt;&lt;br /&gt;So I decided that rather than cursing every time I have to manually expand a property I would instead fix the problem.  Simply manipulating the .snippet files in the directory mentioned earlier does the trick.&lt;br /&gt;&lt;br /&gt;I copied the "prop" snippet from the VS2005 directory into that for 2008 and renamed the "prop" snippet in 2008 "aprop" ("propa" was taken).  You just need to be sure you edit the snippet XML to rename the snippet's shortcut and name as well, they are the values that show up in the IDE.&lt;br /&gt;&lt;br /&gt;An interesting side note to this: Having forgetting to update the snippet shortcut and name in its XML, I tried it out and discovered that VS recognizes the duplicate names.  It prompts you with "Multiple Snippets" and you must make another choice.  Neat.  Someone was thinking.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-746979058869747733?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/746979058869747733/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=746979058869747733' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/746979058869747733'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/746979058869747733'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2008/03/c-prop-shortcut-in-visual-studio-2008.html' title='C# &quot;prop&quot; shortcut in Visual Studio 2008'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-4321794420259445600</id><published>2008-03-20T08:59:00.006-04:00</published><updated>2008-03-31T16:38:35.976-04:00</updated><title type='text'>Old hardware + young kid = tearful parent</title><content type='html'>It all started with Alex.  A few days ago my friend Alex asked me if my web sites were still down.  You see, I host a couple of web sites on an old machine at home.  It's mostly just personal stuff but there's some (very little really) professionally relevant content on one of the sites.  Unfortunately, the machine is starting to break down.  The fan squeaks and rattles on occasion, I've had a hard drive inexplicably fail and then return to life and the board is just old and slow for what I need it to do.  Despite this, yesterday morning I turned the server back on.&lt;br /&gt;&lt;br /&gt;Some time in the middle of the morning I remembered that I wanted to check to see if the machine had actually gotten up and running, so I hit the sites on it, one of which is my personal photo browser.  In doing this, I started browsing early photos of my son.  Then the Dan Fogelberg song "Longer" popped into my head.  So I downloaded the MP3 from the music collection also hosted on this box at home.  I listened to it a few times and got to thinking about my kid.  I can't say that I've ever been a particularly emotional person, but it's amazing what a kid will do to you.  I'm fortunate to have a private office tucked away in a quiet hallway.&lt;br /&gt;&lt;br /&gt;So yesterday evening, after putting Spencer to bed, I put this together:&lt;br /&gt;&lt;br /&gt;&lt;object height="350" width="425"&gt; &lt;param name="movie" value="http://www.youtube.com/v/ia5FFpXVDjI"&gt;  &lt;embed src="http://www.youtube.com/v/ia5FFpXVDjI" type="application/x-shockwave-flash" height="350" width="425"&gt;&lt;/embed&gt;  &lt;/object&gt;&lt;br /&gt;&lt;br /&gt;Now I just need to put this video into a digital photo frame that I can hang above Spencer's time out chair to help dissipate the frustration a 2-year-old can create.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-4321794420259445600?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/4321794420259445600/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=4321794420259445600' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/4321794420259445600'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/4321794420259445600'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2008/03/old-hardware-young-kid-tearful-parent.html' title='Old hardware + young kid = tearful parent'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-4601178792543137442</id><published>2008-03-13T09:54:00.006-04:00</published><updated>2008-03-13T10:15:17.224-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio'/><category scheme='http://www.blogger.com/atom/ns#' term='csharp'/><title type='text'>abstract VS. virtual explained</title><content type='html'>Something I struggled with for a while when first getting into C# was the difference and use of the 'abstract' and 'virtual' keywords.  Here is my simple explanation:&lt;br /&gt;&lt;br /&gt;abstract - Members modified by this keyword MUST be defined in an abstract class and be implemented on any concrete (non-abstract) class that extends the class the member is defined on. (This corresponds to the 'MustOverride' keyword in VB.NET.)&lt;br /&gt;&lt;br /&gt;virtual - Members modified by this keyword CAN be overriden on a concrete class that extends the class that defines the member.  (This corresponds to the 'Overridable' keyword in VB.NET.)&lt;br /&gt;&lt;br /&gt;C# Example:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;abstract class AbstractClass&lt;br /&gt;{&lt;br /&gt; protected void NotModifiedMethod() { }&lt;br /&gt; protected abstract void AbstractMethod();&lt;br /&gt; protected virtual void VirtualMethod() { }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class ConcreteClass : AbstractClass&lt;br /&gt;{&lt;br /&gt; //This HAS to be overriden because it's abstract&lt;br /&gt; protected override void AbstractMethod() { }&lt;br /&gt;&lt;br /&gt; //This CAN be overriden because it's virtual&lt;br /&gt; protected override void VirtualMethod()&lt;br /&gt; {&lt;br /&gt;  base.VirtualMethod();&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; //You CAN NOT do this, because NotModifiedMethod is not&lt;br /&gt; //marked as abstract or virtual&lt;br /&gt; protected override void NotModifiedMethod() { }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;VB.NET Example:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;MustInherit Class AbstractClass&lt;br /&gt;&lt;br /&gt; Protected Sub NonModifiedMethod()&lt;br /&gt; End Sub&lt;br /&gt;&lt;br /&gt; Protected MustOverride Sub MustOverrideMethod()&lt;br /&gt;&lt;br /&gt; Protected Overridable Sub OverridableMethod()&lt;br /&gt; End Sub&lt;br /&gt;&lt;br /&gt;End Class&lt;br /&gt;&lt;br /&gt;Class ConcreteClass&lt;br /&gt; Inherits AbstractClass&lt;br /&gt;&lt;br /&gt; 'This HAS to be overriden because it's marked MustOverride&lt;br /&gt; Protected Overrides Sub MustOverrideMethod()&lt;br /&gt; End Sub&lt;br /&gt;&lt;br /&gt; 'This CAN be overriden because it's marked Overridable&lt;br /&gt; Protected Overrides Sub OverridableMethod()&lt;br /&gt;  MyBase.OverridableMethod()&lt;br /&gt; End Sub&lt;br /&gt;&lt;br /&gt; 'You CAN NOT do this, because NotModifiedMethod is not&lt;br /&gt; 'marked as MustOverride or Overridable&lt;br /&gt; Protected Overrides Sub NonModifiedMethod()&lt;br /&gt;  MyBase.NonModifiedMethod()&lt;br /&gt; End Sub&lt;br /&gt;&lt;br /&gt;End Class&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-4601178792543137442?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/4601178792543137442/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=4601178792543137442' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/4601178792543137442'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/4601178792543137442'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2008/03/abstract-vs-virtual-explained.html' title='abstract VS. virtual explained'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-8530996962287054672</id><published>2008-02-20T07:36:00.000-05:00</published><updated>2008-02-20T07:36:58.477-05:00</updated><title type='text'>Interfacing Hardware with .NET</title><content type='html'>I went to &lt;a href="http://www.tvug.net/"&gt;my local .NET user group&lt;/a&gt; meeting last night and watched a very exciting presentation by &lt;a href="http://www.brianpeek.com"&gt;Brian Peek&lt;/a&gt; on interfacing hardware with .NET.  The presentation focused around the use of &lt;a href="http://www.phidgets.com"&gt;Phidgets&lt;/a&gt; USB controller boards to read and control various inputs and outputs.  Phidgets has the controller boards as well as a whole host of input devices themselves for factors such as RFID scanning, temperature, position/rotation, and light.  They also have some small servo motors.  To round it all out, they provide APIs for .NET, Visual Basic, VBA,  LabView, Java, Delphi, C and C++.  The examples Brian showed us looked ridiculously simple to program with the API they provide.  It certainly puts a new spin on the various ideas I've had over the years for doing home automation.&lt;br /&gt;&lt;br /&gt;The last part of Brian's presentation was about interfacing with the Wiimote from .NET using the WiimoteLib managed library he developed.  He put everything together and showed us a simple R/C car controlled by a Phidgets digital i/o board using the Wiimote as the remote control.  It was the first time I'd ever seen a .NET user group so enthralled.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-8530996962287054672?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/8530996962287054672/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=8530996962287054672' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/8530996962287054672'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/8530996962287054672'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2008/02/interfacing-hardware-with-net.html' title='Interfacing Hardware with .NET'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-5648650349822351213</id><published>2008-02-19T09:29:00.000-05:00</published><updated>2008-02-19T09:30:01.166-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='productivity'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='development'/><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio'/><title type='text'>Lingering check-outs: Increasing VS Build Stability</title><content type='html'>&lt;span style="font-size:130%;"&gt;&lt;/span&gt;For those of you who use the checkout-modify-checkin method of source code control within Visual Studio (I.e. many Visual Source Safe users) here's some advise to increasing integration ease and build stability between developers and a build system.&lt;br /&gt;&lt;br /&gt;As you start to share more VS projects, it's important to be aware of what you have checked out, particularly the project files.  When adding items, if you check in the project file, but not the new item itself, the project will not build because of the missing item in source control.  However, if you leave the project file checked out while you work on the new item, another developer won't be able to checkout the project to modify it or add items to it because of your exclusive checkout.  What will often happen is that one developer is in the process of building the new item when someone else needs to work with the project.  So the first developer checks in both the project and the new item.  However, the other developer still can't build the project due to the half finished item.  This leads to wasted time while the unfinished, breaking code is commented out and checked in.  This results in confusing noise in source file history.&lt;br /&gt;&lt;br /&gt;The best way of avoiding this scenario is to keep project files checked in as much as possible.  My experience has shown the following process for adding items to projects to be most affective:&lt;br /&gt;&lt;br /&gt;- Let Visual Studio check out the project when adding the new item.&lt;br /&gt;- Immediately check in the project and new item as it was added.  Generally a build test isn't necessary on new items because they are void of non-compiling code.  (Continuous Integration can help ensure this even if your local build doesn't work due to other changes you are making.)&lt;br /&gt;- Proceed to edit the new item which will need to be checked back out.&lt;br /&gt;&lt;br /&gt;By using this procedure the project file gets checked in and the new (empty) item is added to source control resulting in a successful build.  Now when another developer needs to modify the project or add an item to it, they'll get the updated project as well as the empty item which will compile.  They can then keep working without compile problems.&lt;br /&gt;&lt;br /&gt;Here are a few other things I've found to help:&lt;br /&gt;- If you don't already, try using Visual Studio's Pending Checkins toolbox window so you can easily see what is checked out to you within the solution.  It's much easier than searching thru the solution explorer or using VSS explorer.  Using this reduces the likelihood of forgetting to check in a file.&lt;br /&gt;- Don't let Visual Studio automatically check out files.  You'll be much more likely to remember that you need to check files in if you were forced to acknowledge their checkout.&lt;br /&gt;&lt;br /&gt;I realize that another solution to this problem is to use the modify-merge-commit method.  However, the fact is that many development teams use Visual Source Safe, and VSS doesn't have the best merge tools so the exclusive checkout method is preferred for it's stability.&lt;br /&gt;&lt;br /&gt;Even working on aggressive projects with many developers working in the same projects, I've found that 2 developers are rarely working in the same exact file(s).  Using this technique to maintain the project integrity goes a long way to reducing interference between developers.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-5648650349822351213?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/5648650349822351213/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=5648650349822351213' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/5648650349822351213'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/5648650349822351213'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2008/02/lingering-check-outs-increasing-vs.html' title='Lingering check-outs: Increasing VS Build Stability'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-8292749124024990977</id><published>2008-02-12T03:16:00.001-05:00</published><updated>2008-02-12T03:32:12.342-05:00</updated><title type='text'>Enlightening Insomnia</title><content type='html'>It's rather interesting that so much mental stimulation can come out of insomnia.&lt;br /&gt;&lt;br /&gt;I recently had a side job doing technical editing for a technology book.  It involved lots of reading.  My wife works evenings and we have a toddler so my time after work is consumed by him so I wasn't able to do much work on my reviewing until after 8 pm most nights.  As a result I struggled to finish the evening's block of work to me nightly fatigue.  However, after I finished, I'd check email and get distracted by something that would lead to continually cascading diversions until before I knew it, the little hand on the clock had worked it's way past 1.  There I'd be more awake then when I put my son to bed almost 5 hours prior.  Of course, the very fact I stayed up too late would be the source of the next evening's difficulties.  Oh the vicious cycle.&lt;br /&gt;&lt;br /&gt;At the moment it's almost 3:30 AM.  I went to bed early quite tired and with a headache.  I think I slept for a few hours, then awoke for my nightly fight with the cat over my claim of the bed.  This was followed by an hour+ of tossing and turning as I thought about work and side projects, other miscellaneous distractions and my resurfacing headache.  After a while I gave up, took some pills and came to the computer.  I have since spent about 30 seconds checking email and several hours writing blog posts and looking up random word definitions on google.&lt;br /&gt;&lt;br /&gt;I wish I had a hibernate button.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-8292749124024990977?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/8292749124024990977/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=8292749124024990977' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/8292749124024990977'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/8292749124024990977'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2008/02/enlightening-insomnia.html' title='Enlightening Insomnia'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-666130686210162296</id><published>2008-02-12T03:10:00.000-05:00</published><updated>2008-02-12T03:10:57.797-05:00</updated><title type='text'>Developers today: Learning to fish</title><content type='html'>&lt;a href="http://p2p.wrox.com/pop_profile.asp?mode=display&amp;amp;id=4428"&gt;I have been a member&lt;/a&gt; of the &lt;a href="http://p2p.wrox.com"&gt;Wrox programmer to programmer (p2p) forum&lt;/a&gt; for many years now.  When I first joined it, the forum was a standard mailing list community populated by a real good bunch of folks including some Wrox authors themselves.  I recall most of the questions to be fairly thought out and asked by people who had run out of options trying to solve their problems.  I started as a new developer learning classic ASP.  I had books, I read them.  I tried code examples and experimented with new things in an effort to understand how things worked and to educate myself so I could do my job.  But when I hit a brick wall or just wanted to understand why some code behaved the way it did I would email the list.  I got a lot of great help there and subsequently met a good friend through the list.  I owe much of my initial education in web and ASP development to the books and that list.&lt;br /&gt;&lt;br /&gt;In part due to a feeling of obligation to give back to the digital community that helped me and simply because I like to educate people by sharing my experience, today my participation on the forum is that of a contributor instead of an inquisitor.  I enjoy helping people learn and understand that which I can explain.  Even when a question is asked about a topic I might be unfamiliar with I think about a solution and try to provide suggestions, even if they are only abstract, conceptual ideas.  Often I become intrigued with the question and stop what I'm working on, to the detriment of my own productivity, and try to solve it myself in an effort to quench my own curiosity.  Never have I done so without learning something new. &lt;br /&gt;&lt;br /&gt;This nature of mine is what makes me a successful software developer and is, I believe, a trait necessary to those that are in the same profession.  I enjoy solving problems and exploring the technologies I use to find better and faster ways to solve those problems.  Most often I find a problem I am having has already been had by others and that there are solutions available within a short distance of a thoughtful search.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:180%;"&gt;Getting the Fish&lt;/span&gt;&lt;br /&gt;It seems that more and more people pursuing software development lack the natural tendency to solve problems.  I am finding that an increasing number of participants on the p2p forum are looking only for the answer to today's riddle and not an explanation of the underlying problem.  They want sample code or in many cases, they just want someone to do it for them.  In extreme cases a post contains what suspiciously looks like a homework assignment with the query "answer these questions", without so much as a "please".  I highly doubt the poster is providing a "quiz of the day" to help us keep our minds sharp".&lt;br /&gt;&lt;br /&gt;In the cases of an inquiry for an explicit answer, most often a few seconds of searching will reveal countless pages of sample code or reference documentation relating to the problem at hand.  It baffles me to think that someone likely spent more time writing a forum post than it would have taken to search and find the answer.  This is evident by the number of responses on the forum that are simply links to other forum threads, articles, tutorials, documentation or simply a google search with the keywords of the original post topic.  Smart contributors aren't likely to spend their time regurgitating available information.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:180%;"&gt;Learning to Fish&lt;/span&gt;&lt;br /&gt;I hesitate to provide discreet answers to questions that I know a poster should be able to solve on their own.  Often I'll reply with a question to which the answer should reveal the solution.  I want to help people learn to think about the problem or how to solve it instead of just providing them the answer.&lt;br /&gt;&lt;br /&gt;A short post that simply says "here's my code, please fix it" (which I could easily do so) is less likely to get a response from me than one that has been &lt;a href="http://www.catb.org/%7Eesr/faqs/smart-questions.html"&gt;well thought out&lt;/a&gt; and takes longer to read.  The former is simply a cop-out while the latter conveys the poster's interest in understanding the problem.  It is surprisingly easy to spot posters who are genuinely stuck and are just missing something tricky that I've encountered before.  The answer is easy to provide and an explanation gives the inquirer a tidbit of knowledge that is not so easy to find.  Any case where the explanation is far more valuable than the answer itself is much more enticing to reply to with the goal, of course, being that the person asking will obtain some knowledge that will help them in the future to solve similar problems.&lt;br /&gt;&lt;br /&gt;The inherent nature of problem solving seems to be missing in more and more people.  I suppose this observation is simply influenced by the effects of the nature itself.  People who know how to solve problems are not the ones asking for discreet answers.  They are finding answers on their own.  However, I refuse to believe that they are absent altogether.  I often find a solution to a problem I'm facing, but still don't understand why the solution works, or why the problem exists in the first place.  Most of my own inquiries on the forum are explanations of the problem I had, the solution I found and the question of whether others have encountered this and why it works the way it does.  These posts are quests for further knowledge of the question and answer, not the answer itself.  Unfortunately, these questions often go unanswered.  Occasionally they spark very stimulating conversation that, while not necessarily answering the question, forces further exploration of the problem.  These are my favorite threads.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:180%;"&gt;Availability of fish&lt;/span&gt;&lt;br /&gt;Analogous to a grocery store, the internet is a grand marketplace of food for the knowledge appetite.  Are people becoming less capable of solving problems due to the access to answers?  Is this eliminating the need to know how to the grow knowledge and solve problems?  Have people become complacent or simply lazy by the prospect that answers are out there and they need not know themselves how to solve them?  I hope not.  My goal is to help people understand the why and the how and not just find the what.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-666130686210162296?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/666130686210162296/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=666130686210162296' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/666130686210162296'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/666130686210162296'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2008/02/developers-today-learning-to-fish.html' title='Developers today: Learning to fish'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-5256380673400773384</id><published>2008-01-29T15:27:00.000-05:00</published><updated>2008-01-29T16:54:22.936-05:00</updated><title type='text'>Moving windows from screen to screen</title><content type='html'>I've been using 2 displays to do software development for many years now and found it makes things significantly easier.  However, I've become increasingly irritated with the process of moving windows to different screens as I use them.  This has been exacerbated by the fact that my new work laptop has a resolution that doesn't match that of the external screen, leaving disparate display sizes.  I'm often moving applications back and forth in order to see more or simply organize them for more useful views. &lt;br /&gt;&lt;br /&gt;Although it certainly isn't very new, I only recently discovered a very handy tool that solves this problem.  &lt;a href="http://www.mediachance.com/free/multimon.htm"&gt;Oscar's Multi-Monitor Taskbar&lt;/a&gt; is a free tool that adds a taskbar to secondary monitors.  The additional taskbar shows the buttons for the applications that are on the same screen, while those buttons are absent from the main windows taskbar.  It also adds a button to each window title bar next to the min/maximize buttons that performs single click window relocation between screens.  This screen relocating can also be performed using shortcut keys (CTRL-ALT-LeftArrow/RightArrow).  While the taskbar tool looks very useful, this implementation of it has some distracting side effects.  The real taskbar flashes with partial button imagines when you switch between apps.&lt;br /&gt;&lt;br /&gt;Fortunately, there is also a stripped down version of the tool that just adds the screen switching buttons.  The one drawback I found is that this version lacks the shortcut keys.  Regardless, a single click is considerably better than restore-drag-maximize.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-5256380673400773384?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/5256380673400773384/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=5256380673400773384' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/5256380673400773384'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/5256380673400773384'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2008/01/moving-windows-from-screen-to-screen.html' title='Moving windows from screen to screen'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-2696433770156936948</id><published>2008-01-29T15:00:00.000-05:00</published><updated>2008-01-29T15:27:15.619-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='productivity'/><category scheme='http://www.blogger.com/atom/ns#' term='technology'/><title type='text'>Wallpaper and screen savers for IT people</title><content type='html'>I am an information technology professional, a software developer to be precise.  I spend nearly my entire work day sitting in front of a computer.  If I'm not at the computer I'm either reading a trade magazine or a programming book, down the hall talking with other developers or slurping ramen noodles while watching/listening to a technology podcast.  I also have a 2 year old who, if I may say so, is rather cute.&lt;br /&gt;&lt;br /&gt;What then is my desktop background?  It's the ultra plain and boring Windows default teal blue.  It's not a picture of my kid, pet, house or favorite vacation spot.  It's a solid wall of lifeless monochromatic color.&lt;br /&gt;&lt;br /&gt;What then is my screen saver?  It's not beziers or starfields or 3d flower boxes.  It's the default black screen with the Windows XP floating logo.  Almost as boring as the wallpaper, but with movement.&lt;br /&gt;&lt;br /&gt;I see banners for screen savers or hear technical people talking about power toys that provide nifty screen savers and wall paper goodness.  Who has time for that?  There's work to be done!  What are these information workers doing that allows them to spend time staring at their computer's desktop wallpaper?  And then staring long enough for their screen saver to kick in?? Don't they have work to do?  Don't they have useless desktop add-on reviews to write?&lt;br /&gt;&lt;br /&gt;And what about the screen savers?  Do we even need them any more?  Sure they were useful when we ran monochrome green CRTs, I suppose ATM and POS displays are legitimate applications, but everyone in my office runs a laptop with an external flat panel display.  What's the purpose of the screen saver now apart from killing productivity?  Do out LCDs really need saving?  The only useful screen saver I see (or rather don't see) is the auto power-down mode.&lt;br /&gt;&lt;br /&gt;If you are going to leave your workstation long enough for the screen saver to kick in, let it power off automatically or just shut it off and save a few watts .  I'm sure your desk chair won't be any less entertained.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-2696433770156936948?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/2696433770156936948/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=2696433770156936948' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/2696433770156936948'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/2696433770156936948'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2008/01/wallpaper-and-screen-savers-for-it.html' title='Wallpaper and screen savers for IT people'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-8738633638262315889</id><published>2008-01-23T21:48:00.001-05:00</published><updated>2008-01-29T09:48:02.425-05:00</updated><title type='text'>Fixing Vendor Data: Malformed PDFs and Internet Explorer</title><content type='html'>I encountered an interesting problem today dealing with PDFs.  The online Chilton applications I manage have over 10 gigabytes (75,000+) technical service bulletins in PDF form.  Today we got a support call about some of them rendering to the browser as plain ASCII.  I attempted to reproduce the problem on my system but found nothing wrong.  After considering that it might be a browser issue I tried Internet Explorer and, sure enough, I could reproduce it.  I tried several PDFs in Internet Explorer, FireFox and Opera.  Only Internet Explorer had the problem.  Instead of launching Adobe Reader and displaying the PDF in it, I got the raw contents of the PDF file in the browser in plain text.&lt;p&gt;I started comparing the contents of the PDFs to see if the offending ones looked corrupt.  While my PDF reading skills are quite those of Adobe Reader, I discerned that the files didn't seem to be messed up. The PDF headers and footers looked normal.  One thing I noticed was a point difference in the PDF version number in the file itself.  I could imagine this could be the culprit.  After all, all 3 browsers use the same Adobe Reader plug-in and the offending files worked fine in Firefox and Opera.&lt;/p&gt;&lt;p&gt;I wondered if there might be something amiss with the mime types that was throwing something off.  This was another longshot but I checked away.  After a few minutes with Fiddler, all looked kosher.&lt;/p&gt;&lt;p&gt;I went back to the PDF contents.  After looking at some that worked and others that didn't I noticed that the ones that caused the problem had several blank lines at the beginning.  In a test with a single file I removed what I thought to be harmless blank lines and viola, the problem was solved.  Apparently Internet Explorer doesn't just push the PDF off to the reader based on the HTTP content type (application/pdf) but was actually reading the file.  When it encounter something other than the typical open bytes of a PDF (%PDF-) it decided that it would just dump it out as plain text instead of handing off to the appropriate application.  It seems that the other browsers don't do this and the extra bytes in the file are harmless to the PDF itself.&lt;/p&gt;&lt;p&gt;I ended up writing a fairly simple app to search the file byte by byte to find what should be the correct starting point.  Simply stripping out a series of whitespace bytes (byte value 10), the files get cleaned up and work just fine.&lt;/p&gt;&lt;p&gt;Yet another story to reinforce that you can't always trust your vendor's data.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-8738633638262315889?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/8738633638262315889/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=8738633638262315889' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/8738633638262315889'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/8738633638262315889'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2008/01/fixing-vendor-data-malformed-pdfs-and.html' title='Fixing Vendor Data: Malformed PDFs and Internet Explorer'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-5157181476707510951</id><published>2008-01-17T22:25:00.001-05:00</published><updated>2008-01-17T22:38:05.599-05:00</updated><title type='text'>Side gig: Wrox book Technical Editor</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://media.wiley.com/product_data/coverImage/9X/04701875/047018759X.jpg"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 100px; height: 125px;" src="http://media.wiley.com/product_data/coverImage/9X/04701875/047018759X.jpg" alt="" border="0" /&gt;&lt;/a&gt;My friend in Holland, &lt;a href="http://imar.spaanjaars.com/"&gt;Imar Spaanjaars&lt;/a&gt; is putting the finishing touches on a new book &lt;a href="http://www.wrox.com/WileyCDA/WroxTitle/productCd-047018759X.html"&gt;Beginning ASP.NET 3.5 : in C# and VB&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I took on the role of Lead Technical Editor.  It was a tough and time consuming but rewarding process.  I learned about some of the new features that Microsoft has released with ASP.NET 3.5, notably LINQ.  It also gave me a chance to play in an environment that I don't usually use, the Express editions of the Visual Studio product family.  I also used some of the controls that were introduced with 2.0 that I don't normally use but probably should.&lt;br /&gt;&lt;br /&gt;Mostly, this project gave me a chance to work closely with Imar (as much as you can with an ocean between you).  I have known him for many years from our existence on the &lt;a href="http://p2p.wrox.com"&gt;Wrox p2p forums&lt;/a&gt; and had the fine opportunity to visit him in Holland while I was on a business trip.  When he's not off writing a book we have the occasional technical chat on IM and I think we both get a lot from it.  It was nice to work on an official project with him despite it not involving any actual software development.&lt;br /&gt;&lt;br /&gt;Overall a worthwhile experience, although it will be nice to have some time off before the next extracurricular project.  I know that he'll be ecstatic when it's finished.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-5157181476707510951?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/5157181476707510951/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=5157181476707510951' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/5157181476707510951'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/5157181476707510951'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2008/01/side-gig-wrox-book-technical-editor.html' title='Side gig: Wrox book Technical Editor'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-8724083027078012557</id><published>2008-01-17T22:25:00.000-05:00</published><updated>2008-01-17T22:25:39.408-05:00</updated><title type='text'>Another yearly post</title><content type='html'>Well, it's been another whole year (+1 day) since I posted here.  "What's been going on", you are no doubt wondering.  Well...&lt;br /&gt;&lt;br /&gt;The year has changed.  That's right it's 2008 now!  Time to buy another calendar.&lt;br /&gt;&lt;br /&gt;The new job is going well.  I started working for Thomson Delmar Learning in November last year.  Then Thomson sold us to a private holdings company and we assumed the new identity of Cengage Learning.  I still have a job, that is good.  But even if I didn't have this one any more I am not too worried as there are plenty of jobs for .NET developers in my area.  (I silently wonder if I shouldn't be gazing out at more luscious pastures...)  I like my job though so in the off chance anyone I work with is reading this (unlikely) don't be worried.  Despite all the changes ensuing after the company's sale not much has changed in my little world which incidentally is that of Chilton Automotive.  I'm in charge of three main web product sites: &lt;a href="http://www.chiltonpro.com/"&gt;chiltonpro.com&lt;/a&gt;, &lt;a href="http://www.chiltondiy.com/"&gt;chiltondiy.com&lt;/a&gt; and chiltonlibrary.com.  It's interesting work and a good place to be.  It's a 10 minute walk from my house so I haven't driven to work in nearly 14 months which is very nice.&lt;br /&gt;&lt;br /&gt;Spencer is now 2 and being a 2 year old.  We have been fortunate and he has not had any major problems aside from the occasional diaper rash and minor cold.  He sleeps well, eats OK and is pretty happy most of the time, mostly to the credit of his mother.&lt;br /&gt;&lt;br /&gt;Aside from that it's pretty much the status quo here.  There are a few more things that I'll discuss in other posts.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-8724083027078012557?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/8724083027078012557/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=8724083027078012557' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/8724083027078012557'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/8724083027078012557'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2008/01/another-yearly-post.html' title='Another yearly post'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-257284651072783361</id><published>2007-01-16T09:29:00.001-05:00</published><updated>2007-01-16T09:38:00.963-05:00</updated><title type='text'>New Kid, New Job, Stale Blog</title><content type='html'>I've only posted once within the last year.  I guess I have been busy.  My&lt;br /&gt;old job kept me very busy so I just didn't have time during the day to write&lt;br /&gt;(plus, if I'd come up with something significant to write I'd probably have&lt;br /&gt;done so).  Then there was the birth of my son Spencer on 11/12/05.  I have&lt;br /&gt;been pretty tied up since then.  In November 05 I started a new job which is&lt;br /&gt;very close to home, requires no commute (ok, 5 minutes by scooter) and is better hours.  So I'll&lt;br /&gt;hopefully take a little more time to write something.  Plus, now that&lt;br /&gt;Spencer is sleeping on a more regular schedule things should be improved.&lt;br /&gt;Now if I could only wean myself off of X-Files repeats.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-257284651072783361?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/257284651072783361/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=257284651072783361' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/257284651072783361'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/257284651072783361'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2007/01/new-kid-new-job-stale-blog.html' title='New Kid, New Job, Stale Blog'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-113819952587152133</id><published>2006-01-25T09:27:00.000-05:00</published><updated>2006-01-25T09:32:05.896-05:00</updated><title type='text'>URL  Rewriting (aka: Wrong tool Charlie)</title><content type='html'>On a &lt;a href="http://p2p.wrox.com/topic.asp?TOPIC_ID=38877"&gt;recent thread&lt;/a&gt; on the Wrox p2p forums, a user posted a link to a &lt;a href="http://msdn.microsoft.com/library/en-us/dnaspp/html/urlrewriting.asp"&gt;4guysfromrolla/MSDN article&lt;/a&gt; regarding URL rewriting:&lt;br /&gt;&lt;br /&gt;The basic idea being to convert complicated URLS like:&lt;br /&gt;&lt;br /&gt;   http://yousite.com/displayCategory.aspx?CategoryID=5&lt;br /&gt;&lt;br /&gt;to something more human friendly such as:&lt;br /&gt;&lt;br /&gt;   http://yoursite.com/products/Widgets&lt;br /&gt;&lt;br /&gt;I started reading the article but stopped shortly into it because I started disagreeing with much of what they were saying.&lt;br /&gt;&lt;br /&gt;They give the impression that web users spend a lot of time typing in complete URLs to get to where they wish to go.  That makes no sense to me.  When was the last time you went to amazon.com and typed in the full URL to a product or "department" you wanted to see?  I can't say I ever had.  Part of this might be the fact that their URLs are very complicated and make no sense (which of course is the whole point to the article referrenced).&lt;br /&gt;&lt;br /&gt;A web user should not need to type in a URL other than the root site address.  In the case of amazon.com, when you want to get to a product, you enter a search for it!  While I like the coolness factor of the whole URL rewriting idea, I think it's a needless addition.  Focus on building a usable search mechanism for your web site/application and you'll provide a much better way for users to access information.&lt;br /&gt;&lt;br /&gt;Another point they make in the article address making your site URLs "hackable".  To paraphrase: "The user should be able to manipulate the URL and have it return something good."&lt;br /&gt;&lt;br /&gt;My alternative? Build a logical and intuitive navigation system.  Perhaps time could be better spent learning some site usability rather than building a technical solution to support "URL hacking" that won't necessarily be all that logical to a user anyway.&lt;br /&gt;&lt;br /&gt;When I think about designing something for the web, I think about how I would direct my dad to go to a page on the site over the phone.  (My dad's a bright guy, computers just aren't his strength.)  Which scenario would you find easier:&lt;br /&gt;&lt;br /&gt;Me: "Hey dad."&lt;br /&gt;Dad: "Hey kid, how do I get to that cheese grader page?"&lt;br /&gt;&lt;br /&gt;(Scenario 1)&lt;br /&gt;Me: "Type into your browser address bar..."&lt;br /&gt;Dad: "What's that?"&lt;br /&gt;Me: "(*sigh*) That's the white box at the top where you normally type in 'google.com'."&lt;br /&gt;Dad: "Oh right, ok..."&lt;br /&gt;Me: "Type in mysite dot com slash products slash kitchen slash cheese grader"&lt;br /&gt;Dad: "Is there a space in cheese grader?"&lt;br /&gt;Me: "Nope"&lt;br /&gt;Dad: "Ok, now what."&lt;br /&gt;Me: "(*sigh*) Hit enter or click the go button."&lt;br /&gt;Dad: "Hmm... didn't work."&lt;br /&gt;Me: "Ok, read back what you typed."&lt;br /&gt;Dad: "myside dot com slash product slash... oh wait, I spelled kitchen wrong."&lt;br /&gt;......and so on.&lt;br /&gt;&lt;br /&gt;(Scenario 2)&lt;br /&gt;Me: "Go to mysite dot com"&lt;br /&gt;Dad: "Ok, I'm there now."&lt;br /&gt;Me: "Type in cheese grader in the search box and click search. You should get back links to all the cheese grader products."&lt;br /&gt;Dad: "Ok... Ah there they are.  Thanks."&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Expecting users to use the URL to navigate/search your site requires them to have some understanding about how URLs work.  The article says that they shouldn't be expected to understand how query strings are used to drive the pages.  If you can't expect them to understand that, then how can or why should we expect them to understand any of it?  More importantly, as I pointed out earlier, eliminate the need all together and build a site with a good search and good navigation and your users can get to where they want with a minimum of key strokes or mouse clicks.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-113819952587152133?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/113819952587152133/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=113819952587152133' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/113819952587152133'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/113819952587152133'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2006/01/url-rewriting-aka-wrong-tool-charlie.html' title='URL  Rewriting (aka: Wrong tool Charlie)'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-112905478104690068</id><published>2005-10-11T14:16:00.000-04:00</published><updated>2006-01-18T08:00:36.183-05:00</updated><title type='text'>Raise your hand if you aren't here.</title><content type='html'>I just got this email from my web host:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;Dear Customer&lt;br /&gt;&lt;br /&gt;To resolve the recent email latency issue, we have deployed a second email system. This is a courtesy note to inform you that your email for geekdork.com has been migrated to the second email system.&lt;br /&gt;...&lt;br /&gt;If you experience any issues with your email, please contact our technical support department and provide as much detail as possible.&lt;br /&gt;&lt;br /&gt;Thank you.&lt;br /&gt;&lt;br /&gt;DiscountASP.NET&lt;br /&gt;http://www.DiscountASP.NET&lt;br /&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-112905478104690068?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/112905478104690068/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=112905478104690068' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/112905478104690068'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/112905478104690068'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2005/10/raise-your-hand-if-you-arent-here.html' title='Raise your hand if you aren&apos;t here.'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-112644623590410554</id><published>2005-09-11T09:42:00.000-04:00</published><updated>2005-09-11T09:43:55.910-04:00</updated><title type='text'>Link: Stuff on my cat</title><content type='html'>A friend just sent me a link to a brilliant web site:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.stuffonmycat.com/"&gt;StuffOnMyCat.com&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Boy, do I have some material for them...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-112644623590410554?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/112644623590410554/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=112644623590410554' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/112644623590410554'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/112644623590410554'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2005/09/link-stuff-on-my-cat.html' title='Link: Stuff on my cat'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-112335818798009873</id><published>2005-08-06T15:13:00.000-04:00</published><updated>2005-08-06T15:56:27.993-04:00</updated><title type='text'>Ashamed of VB.NET ?!</title><content type='html'>I recently read an article regarding .NET techniques on a &lt;a href="http://www.codeproject.com"&gt;programming community site&lt;/a&gt;.  The &lt;a href="http://www.codeproject.com/script/profile/whos_who.asp?vt=arts&amp;id=18901"&gt;author&lt;/a&gt; explained at the end of the article that all the examples were written in C# because that's his personal preference.  His author profile describing his skills mentioned his proficiency at several languages including VB.NET.  With that, he included the parenthetical comment "I’m not proud of this".  &lt;br /&gt;&lt;br /&gt;Why would anyone do this?  Why would anyone go out of their way to say this?  What is SO damn wrong and shameful about learning, knowing and being proficient at VB.NET?  Whenever I hear people bash VB.NET I have to ask, "What is so grand about C# that makes you so high-and-mighty that you should be ashamed by any association to VB.NET?"&lt;br /&gt;&lt;br /&gt;I work with VB.NET on a daily basis.  That's the language I started with when I dove into .NET.  I also use C# on a daily basis.  Once I learned .NET using a language syntax I was already comfortable with (VB/Script) I easily transitioned into using C# when I could focus on learning the C# syntax and not have to also stress over the .NET semantics.  Frankly, I think this made my .NET skill aquisition that much faster.&lt;br /&gt;&lt;br /&gt;I'll openly (and not shamefully) admit that I prefer working with VB.NET in some areas.  I find that it is much friendlier when writing UI code in Visual Studio.NET (2003).  It plays very nicely with the IDE when working with forms.  However, in my main VS.NET solution all the projects are C# based except for the single VB.NET web application project.  I greatly prefer C# for little reason other than the XML commenting in all the supporting libraries.  However, I find C# to be a pain when building classes.  In VB.NET when you type the first line of a Property, it fills out the rest, creating the structure for the default accessors.  In C# I have to write them all out manually. (Hopefully I haven't missed some VS.NET configuration setting for that.)&lt;br /&gt;&lt;br /&gt;The simple fact that all .NET languages are for most purposes identical in capabilities should make anyone feel that the languages are equal.  Yet so many developers work with C# and steer clear of VB.NET while maintaining a holier-than-thou attitude towards the VBers.  Get over yourselves.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-112335818798009873?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/112335818798009873/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=112335818798009873' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/112335818798009873'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/112335818798009873'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2005/08/ashamed-of-vbnet.html' title='Ashamed of VB.NET ?!'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-112144515091912447</id><published>2005-07-15T12:31:00.000-04:00</published><updated>2005-07-15T14:00:02.876-04:00</updated><title type='text'>Prison vs. Work</title><content type='html'>&lt;table style="font-size: 85%;" border="1" cellspacing="0"&gt;&lt;tbody&gt;&lt;tr valign="top"&gt;&lt;td&gt;&lt;b&gt;IN PRISON&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;b&gt;AT WORK&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr valign="top"&gt;&lt;td&gt;you spend the majority of your time in an 10X10 cell&lt;/td&gt;&lt;td&gt;you spend the majority of your time in an 8X8 cubicle&lt;/td&gt;&lt;/tr&gt;&lt;tr valign="top"&gt;&lt;td&gt;you get three meals a day&lt;/td&gt;&lt;td&gt;you get a break for one meal and you have to pay for it&lt;/td&gt;&lt;/tr&gt;&lt;tr valign="top"&gt;&lt;td&gt;you get time off for good behavior&lt;/td&gt;&lt;td&gt;you get more work for good behavior&lt;/td&gt;&lt;/tr&gt;&lt;tr valign="top"&gt;&lt;td&gt;the guard locks and unlocks all the doors for you&lt;/td&gt;&lt;td&gt;you must often carry a security card and open all the doors for yourself&lt;/td&gt;&lt;/tr&gt;&lt;tr valign="top"&gt;&lt;td&gt;you can watch TV and play games&lt;/td&gt;&lt;td&gt;you could get fired for watching TV and playing games&lt;/td&gt;&lt;/tr&gt;&lt;tr valign="top"&gt;&lt;td&gt;you get your own toilet&lt;/td&gt;&lt;td&gt;you have to share the toilet with some people who pee on the seat&lt;/td&gt;&lt;/tr&gt;&lt;tr valign="top"&gt;&lt;td&gt;they allow your family and friends to visit&lt;/td&gt;&lt;td&gt;you aren't even supposed to speak to your family&lt;/td&gt;&lt;/tr&gt;&lt;tr valign="top"&gt;&lt;td&gt;all expenses are paid by the taxpayers with no work required&lt;/td&gt;&lt;td&gt;you get to pay all your expenses to go to work, and they deduct taxes from your salary to pay for prisoners&lt;/td&gt;&lt;/tr&gt;&lt;tr valign="top"&gt;&lt;td&gt;you spend most of your life inside bars wanting to get out&lt;/td&gt;&lt;td&gt;you spend most of your time wanting to get out and go inside bars&lt;/td&gt;&lt;/tr&gt;&lt;tr valign="top"&gt;&lt;td&gt;you must deal with sadistic wardens&lt;/td&gt;&lt;td&gt;they are called managers&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-112144515091912447?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/112144515091912447/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=112144515091912447' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/112144515091912447'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/112144515091912447'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2005/07/prison-vs-work.html' title='Prison vs. Work'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-112079297173121715</id><published>2005-07-07T23:19:00.000-04:00</published><updated>2006-01-25T09:36:29.373-05:00</updated><title type='text'>GeekDork.Baby</title><content type='html'>My wife and I had another ultrasound appointment today. Got several 2D AND 3D pictures. Plus we got about 9 minutes of videotape along the way. The 3D ultrasound stuff is pretty damn cool.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-112079297173121715?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/112079297173121715/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=112079297173121715' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/112079297173121715'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/112079297173121715'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2005/07/geekdorkbaby.html' title='GeekDork.Baby'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-111986234121750987</id><published>2005-06-27T04:45:00.000-04:00</published><updated>2005-06-30T08:45:13.356-04:00</updated><title type='text'>web.config Intellisense</title><content type='html'>A recent &lt;a href="http://www.codeproject.com"&gt;CodeProject&lt;/a&gt; article discusses &lt;a href="http://www.codeproject.com/dotnet/intellisenseconfig.asp"&gt;Howto: Enable Intellisense Support for Configuration Files In VS.NET 2003&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Seems to work pretty well and I can see how the same technique could be applied to custom XML files in applications.  The one problem I found seems to be that the XSD provided with the article download doesn't appear to support the &lt;location&gt; tag of the config.  I couldn't find it in anywhere in the XSD and unfortunately my XSD skills aren't so great otherwise I'd fix it.  I may try at some point once I get some more understanding of building XSDs.&lt;br /&gt;&lt;br /&gt;Updated:&lt;br /&gt;&lt;br /&gt;It turns out the article's comments section had some suggestions on fixing the &lt;location&gt; element problem.  So I did some reading and tweaked the XSD.  It seems to now validate properly with &lt;location&gt; elements where they are allowed.  You can download my modified XSD here: &lt;a href="http://www.geekdork.com/dotnet/clrconfig.xsd"&gt;http://www.geekdork.com/dotnet/clrconfig.xsd&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Another update (6/27):&lt;br /&gt;&lt;br /&gt;Apparently, putting that xmlns attribute in the &lt;configuration&gt; element of a web.config causes it to break.  There was no mention of this in anything I read about it. It makes intellisense work when it's there and used in Visual Studio, but completely seizes the application.  Not such a good thing.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-111986234121750987?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/111986234121750987/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=111986234121750987' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/111986234121750987'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/111986234121750987'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2005/06/webconfig-intellisense.html' title='web.config Intellisense'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-111973378820152895</id><published>2005-06-25T17:02:00.000-04:00</published><updated>2005-06-25T17:09:48.206-04:00</updated><title type='text'>A Page.GetUrl() Method</title><content type='html'>A recent post on the Wrox/Wiley programmer to programmer forum asked the question:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;"How do I get the URL to a page without hardcoding the page URL?"&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;While it would be a very nice feature to have in .NET it seems to make sense that there is no method that will generate a URL for you to a page even though we have strongly typed code-behind classes that often times drive the page. Consider that the pages are just ASPX files that can be named anything and can live anywhere in your application structure. They can be derived from any page-derived class in the accessible namespaces (the framework supplied System.Web.UI.Page class, or any class that you create in your application assemblies that was derived from the framework's web page class). This provides us with very flexible design and application structure but as a result we don't have a reliable way to say "give me the URL for X".&lt;br /&gt;&lt;br /&gt;A possible solution to this that solves two problems at once is to create a shared/static "GetUrl" method on the pages. This method provides the root-relative URL to the page that owns the code-behind class as well as specifying required parameters so you don't have to guess at them or encounter problems later on.&lt;br /&gt;&lt;br /&gt;Let's take an example of a class that shows the attributes for some item.  This class lives at the root of our application:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;   ourApplication/ItemAttributes.aspx&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Here's the code-behind class:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;Public Class ItemAttributes&lt;br /&gt;  Inherits System.Web.UI.Page&lt;br /&gt;  ...&lt;br /&gt;  Public Shared Function GetUrl(itemID As Integer, page As Page) As String&lt;br /&gt;     Return page.ResolveUrl("~/ItemAttributes.aspx?itemID=" &amp; itemID)&lt;br /&gt;  End Function&lt;br /&gt;End Class&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The GetUrl() method expects a couple of arguments: first an itemID because we need a reference to some item so we know what item's attributes to show; second, an instance of a Page class. We need the instance of the page class so we can access the ResolveUrl() method. Now, any other pages in the application can create links to this page by calling the public shared method:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;   ItemAttributes.GetUrl(12, Me)&lt;br /&gt;  'returns "/ourApplication/ItemAttributes.aspx?itemID=12"&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;A benefit of this technique is that we get a more robust application that is not quite as suceptible to growing pains. Let's say that we move this page because our application is getting bigger and the pages are getting cluttered. We'll move the page to a directory of common pages:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;   ourApplication/common/ItemAttributes.aspx&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;We can just modify the GetUrl method and all the pages that consume this page link will follow along without a glitch:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;   Return page.ResolveUrl("~/common/ItemAttributes.aspx?itemID=" &amp;amp; itemID)&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now let's imagine that we have to add another querystring value to the page because we now need to get information about the category that this item is in. When we modify our page to look for the querystring value all the page requests will start failing. We don't know all the places that this page is called in the application so we will have to do a pretty good job testing the application to find the now-broken references. However, there is salvation! All we have to do is change the method signature to expect the new argument:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;   Public Shared Function GetUrl(itemID As Integer, categoryID As Integer, page As Page) As String&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now when we try to the build the application we'll get compile errors everywhere that this method is called. We can go and repair all those broken calls. Of course, depending on how you build your pages, you could add an overloaded method that still accepts the original set of arguments and have it call the new method with a default value so you don't have to repair broken calls. This is a great approach if you can build the page to function without the additional information.&lt;br /&gt;&lt;br /&gt;By using this technique you get several advantages:&lt;br /&gt;1. Flexibility to move pages&lt;br /&gt;2. Compile-time debugging (reduces testing and potential customer discoveries of overlooked bugs)&lt;br /&gt;3. Multi-developer teams don't have to waste precious time researching what the page expects for a querystring because the calls have a strongly typed and descriptive signature.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-111973378820152895?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/111973378820152895/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=111973378820152895' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/111973378820152895'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/111973378820152895'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2005/06/pagegeturl-method.html' title='A Page.GetUrl() Method'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-111814024200166953</id><published>2005-06-07T06:27:00.000-04:00</published><updated>2005-06-07T06:30:42.006-04:00</updated><title type='text'>Religious development</title><content type='html'>I just read a short post on the Wrox/Wiley programmer to programmer forum.  The poster's signature read:&lt;br /&gt;&lt;blockquote&gt;Writing software to specification and walking on water is easy.. as long as both are frozen.&lt;/blockquote&gt;How true that is.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-111814024200166953?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/111814024200166953/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=111814024200166953' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/111814024200166953'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/111814024200166953'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2005/06/religious-development.html' title='Religious development'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-111780702086474694</id><published>2005-06-03T09:57:00.000-04:00</published><updated>2005-06-08T10:03:38.916-04:00</updated><title type='text'>Link: Just ignore me when I get crabby like this</title><content type='html'>Eric Sink writes about basic &lt;a href="http://software.ericsink.com/entries/airport_madness.html"&gt;airport etiquette&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;In addition to his comments, I'd like to add the following rule:&lt;br /&gt;&lt;br /&gt;- Stand a minimum of 10 feet away from the baggage claim carousel and do not approach until you think you SEE your bag.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-111780702086474694?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/111780702086474694/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=111780702086474694' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/111780702086474694'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/111780702086474694'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2005/06/link-just-ignore-me-when-i-get-crabby.html' title='Link: Just ignore me when I get crabby like this'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-111694672830431495</id><published>2005-05-24T10:55:00.000-04:00</published><updated>2005-05-24T10:58:48.306-04:00</updated><title type='text'>Gent: Tuesday</title><content type='html'>Went for a very long walk around Gent.&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.geekdork.com/images/Belgium/GentDowntown.jpg"/&gt;&lt;br /&gt;&lt;br /&gt;Very interesting place.  There are the famous towers of three cathedrals plus many more churches across the city.  Lots of really neat alleyways and streets.  Many of the buildings have remarkable faces of intricate wood, stove and iron work.  Very impressive.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-111694672830431495?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/111694672830431495/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=111694672830431495' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/111694672830431495'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/111694672830431495'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2005/05/gent-tuesday.html' title='Gent: Tuesday'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-111691961212231142</id><published>2005-05-24T09:23:00.000-04:00</published><updated>2005-05-24T03:26:52.126-04:00</updated><title type='text'>Gent: Tuesday morning</title><content type='html'>Lovely morning in Gent.  Took a couple quick cameraphone pics from the hotel terrace:&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.geekdork.com/images/Belgium/HotelRoundabout.jpg"/&gt;&lt;br /&gt;The roundabout on the hotel street, a trolly and the trains overhead.&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.geekdork.com/images/Belgium/HotelStreet.jpg"/&gt;&lt;br /&gt;The other direction on the hotel's street.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-111691961212231142?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/111691961212231142/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=111691961212231142' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/111691961212231142'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/111691961212231142'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2005/05/gent-tuesday-morning.html' title='Gent: Tuesday morning'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-111686393662749546</id><published>2005-05-23T17:30:00.000-04:00</published><updated>2005-05-23T11:58:56.630-04:00</updated><title type='text'>Arrived in Belgium</title><content type='html'>I got into Gent, Belgium this morning for a one week visit for the European user group conference I'm attending and presenting at for work.  The express flight was a little late getting to Newark, NJ so I had to rush to make the connection.  Then, of course, we sat at the gate for at least 30 minutes then took a good while to get off the ground.  Didn't leave there till an hour after the planned pushback.  So we arrived late but it didn't really matter because we didn't have anything scheduled for when we got here.&lt;br /&gt;&lt;br /&gt;Somehow I left home without the data cable for the camera I brought so I can't get any good pictures online till after I get home.  But I have my camera phone (with infrared transfer) so I could at least get something.&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.geekdork.com/images/Belgium/HotelView.jpg"&gt;&lt;br /&gt;View from the hotel window.  The building next door blocks the side of the train station overpass that leads into the main square of Gent.&lt;br /&gt;&lt;br /&gt;I walked into the train station and around almost every corner is some stand or shop that sells "Warme Waffles".  The whole place smelled of them which made me very hungry.  However, I can't eat until dinner later on with a contact of ours here.  I'm definately going to have to see about getting a waffle for dessert (apparently that's how it works).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-111686393662749546?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/111686393662749546/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=111686393662749546' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/111686393662749546'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/111686393662749546'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2005/05/arrived-in-belgium.html' title='Arrived in Belgium'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-111670111205302658</id><published>2005-05-21T14:42:00.000-04:00</published><updated>2005-05-21T14:45:12.056-04:00</updated><title type='text'>Added old posts.</title><content type='html'>I added posts from my old blog (there weren't many).  It was reasonably painless apart from trying to figure out what the real times where that posts were made.  The blog pluggin I was using was saving the times wrong. But they didn't seem to be consistantly wrong so I had to do a little estimating or just make them up. Oh well.  They're here now, so I just have to figure out if I'll publish directly to my site or have my site pull the feed and show the results.  I suppose the latter would be better.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-111670111205302658?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/111670111205302658/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=111670111205302658' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/111670111205302658'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/111670111205302658'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2005/05/added-old-posts.html' title='Added old posts.'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-111669615732986635</id><published>2005-05-21T13:18:00.000-04:00</published><updated>2005-05-21T13:22:37.333-04:00</updated><title type='text'>GeekDork.Blog = New Blogger()</title><content type='html'>I broke down a got a new blog. I had tried a blog pluggin on my site, but it just wasn't working out the way I had hoped. So I decided to give Blogger a try. I was about to start looking into importing previous blog posts but just now noticed that I can change the date and time of new posts. So I should be able to put in my old posts without much difficultly. Good thing I don't have hundreds of them! Hopefully this bog will work out better than the old one.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-111669615732986635?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/111669615732986635/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=111669615732986635' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/111669615732986635'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/111669615732986635'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2005/05/geekdorkblog-new-blogger.html' title='GeekDork.Blog = New Blogger()'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-111669909846141666</id><published>2005-05-16T14:28:00.000-04:00</published><updated>2005-05-21T14:11:38.466-04:00</updated><title type='text'>ASP.NET Application reset behavior</title><content type='html'>In the March 2005 asp.netPRO magazine, there is an article by Dino Esposito discussing accessing compile-time code programmatically. He explains how code files are generated from the parsed markup files and then get compiled into temporary assemblies in the ASP.NET temp folder(s). Although he makes a very brief mention of how to actually access this code programmatically, he mostly writes about how ASP.NET works under the hood. Towards the end of the article he notes something that I found very interesting. He writes:&lt;br /&gt;&lt;blockquote&gt;"Each ASP.NET application is allowed a maximum number of page recompiles (with 15 as the default) before the whole application is restarted. ...If the lates compilation exceeds the threshold, the AppDomain is unloaded and the application is restarted. Bear in mind that the atomic unit of code you can unlad in the CLR is the AppDomain, not the assembly. Put another way, you can't unload a single assembly without unloading the whole AppDomain."&lt;/blockquote&gt;&lt;br /&gt;I develop with the "attach when you need to" versus the "hit play/F5 and lauch I.E. every time" technique. I find this to be much more productive and saves the hastle of having to truly restart my application every time. Granted, this introduces some problems because I'm not starting clean every single time but I find that the occassional inconvenience is far outweighed by the time savings of avoiding a the full recompile-load IE-attach sequence.&lt;br /&gt;&lt;br /&gt;When I make file changes that do not require recompiling I go thru many change-save-refresh cycles. I have noticed that most of the time after I refresh there is only a slight delay (sometimes hardly noticable) on the first refresh after a change. I knew that ASP.NET is refreshing its cache of my page but beyond that I was not aware of what was actually going on. Occasionally, the application will seem to hang up, but then return and behave as if I had restarted completely (I'll end up at the login page if I'm in a authenticated application). Based on Esposito's explanation I now understand that I've reached that recompile threshold and my entire application has been restarted. This explains the behavior I've experienced and wondered about.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-111669909846141666?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/111669909846141666/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=111669909846141666' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/111669909846141666'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/111669909846141666'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2005/05/aspnet-application-reset-behavior.html' title='ASP.NET Application reset behavior'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-111669919582239805</id><published>2005-04-21T13:32:00.000-04:00</published><updated>2005-05-21T14:14:05.386-04:00</updated><title type='text'>Stupid Bosses (Not Mine)</title><content type='html'>As a member and moderator on the Wrox/Wiley Publishing programmer to programmer forums, I see lots of silly or simple questions. This is no surprise and expectable when so many people come to the forums as new programmers. However, sometimes after some additional prodding (like asking "Why are you doing is this way instead of that?" I'll learn that they are doing something the way they are "because that's how my boss wants me to do it". It also seems that the way the boss wants it done is rediculously idiotic. A &lt;a href="http://p2p.wrox.com/topic.asp?TOPIC_ID=29386"&gt;recent thread&lt;/a&gt; in an ASP.NET forum led me to learn that the programmer is manually writing out HTML instead of using a DataGrid control because the boss has some kind of weird problem with the built-in .NET controls.&lt;br /&gt;&lt;br /&gt;How the HELL does this happen? Who the hell are the bosses that think this way? This boss in particular has made a decision that makes about as much sense as buying a car and choosing not to drive but to push it instead. S/he is costing their company time and money by forcing the programmer to do a hell of a lot more work than is necessary!&lt;br /&gt;&lt;br /&gt;I am a technology person. It happens that my boss is as well. He still programs while he manages the other developers. He understands the capabilities of the technologies we use if not all of the nitty gritty details of how to implement them. Implementation is my job. I build things the best way I can, by utilizing the resources and tools available. He lets me use the tools I need (where availability and money allow). But somewhere out in the corporate world, there is are bosses who are total idiots and are making their employees jobs a complete pain in the ass while being a detriment to their companies.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-111669919582239805?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/111669919582239805/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=111669919582239805' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/111669919582239805'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/111669919582239805'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2005/04/stupid-bosses-not-mine.html' title='Stupid Bosses (Not Mine)'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-111669937979817505</id><published>2005-03-26T00:32:00.000-05:00</published><updated>2005-05-21T14:16:19.800-04:00</updated><title type='text'>A JAVA iron lung</title><content type='html'>I was installing MSMoney 2003 this evening and happened to scan thru the EULA when I came across this section that I find particularly funny:&lt;br /&gt;&lt;br /&gt;9. NOTE ON JAVA TECHNOLOGY. The SOFTWARE PRODUCT may contain support for programs written in JAVA. JAVA TECHNOLOGY IS NOT FAULT TOLERANT AND IS NOT DESIGNED, MANUFACTURED, OR INTENDED FOR USE OR RESALE AS ON-LINE CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT LIFE SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF JAVA TECHNOLOGY COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE PHYSICAL OR ENVIRONMENTAL DAMAGE. Sun Microsystems, Inc. has required the inclusion of this disclaimer.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-111669937979817505?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/111669937979817505/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=111669937979817505' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/111669937979817505'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/111669937979817505'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2005/03/java-iron-lung.html' title='A JAVA iron lung'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-111669944685653201</id><published>2005-03-18T14:13:00.000-05:00</published><updated>2005-05-21T14:17:26.856-04:00</updated><title type='text'>Eric Sink's Source Control HOWTO</title><content type='html'>&lt;a href="http://www.ericsink.com"&gt;Eric Sink&lt;/a&gt; (founder of &lt;a href="http://www.sourcegear.com"&gt;SourceGear&lt;/a&gt;, maker of &lt;a href="http://www.sourcegear.com/vault"&gt;Vault&lt;/a&gt;) has been writting and is finishing a splendid &lt;a href="http://www.ericsink.com/scm/source_control.html"&gt;Source Control How To&lt;/a&gt;.  He makes some very good comments regarding how must programmers/developers learn what they need to program but are never taught the tools that developers use in real-world software environments (project management, bug tracking and , most importantly, source code version managment).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-111669944685653201?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/111669944685653201/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=111669944685653201' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/111669944685653201'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/111669944685653201'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2005/03/eric-sinks-source-control-howto.html' title='Eric Sink&apos;s Source Control HOWTO'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-111669957160575041</id><published>2005-03-03T10:36:00.000-05:00</published><updated>2005-05-21T14:19:31.606-04:00</updated><title type='text'>Overriding web.config app settings with user.config</title><content type='html'>Some time ago, I was in a situation where I wanted to set local application settings for a web application I was developing to some alternatives without messing with the project's copy of the web.config file.  So I'd change my local copy by making it writable (normally the file was read-only because it is under source control).  Every time I'd get latest version for the project it would either overwrite the file (if I forgot to leave the local copy) or I'd have to merge any changes manually.&lt;br /&gt;&lt;br /&gt;Then I came up with this clever idea to have a little change script which would tickle the XML nodes of the web config file so I could just run that every time I got latest version.  But it still was a pain because I had to remember to perform this action or it was more difficult to maintain.&lt;br /&gt;&lt;br /&gt;Well, I just learned that .NET has a built in solution (that wasn't very well publicized apparently).  Apparently, you can place the attribute [file="user.config"] in the web.config file and it will point to that file for application setting overrides.  So you could then create that file in the application directory to hold your personal overrides for the default app settings.  The file should look like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&amp;lt;appSettings&amp;gt;&lt;br /&gt; &amp;lt;add key="key" value="value" /&amp;gt;&lt;br /&gt;&amp;lt;/appSettings&amp;gt;&lt;/pre&gt;&lt;br /&gt;Note that 'appSettings' is the root node.  The user.config file does not have to exist.  .NET will just ignore a missing file and use the default values in web.config.&lt;br /&gt;&lt;br /&gt;If you do create this file make sure you do not put it into the project (and, thus, source control) so as to avoid overwriting individual's settings.&lt;br /&gt;&lt;br /&gt;I found this in the MSDN article: &lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnbda/html/tdlg_ch4.asp"&gt;Team Development with Visual Studio NET and Visual SourceSafe - Chapter 4: Managing Dependencies&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;There are lots of other details in there that are helpful to know if you are building software in a team environment.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-111669957160575041?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/111669957160575041/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=111669957160575041' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/111669957160575041'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/111669957160575041'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2005/03/overriding-webconfig-app-settings-with.html' title='Overriding web.config app settings with user.config'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-111669985219951164</id><published>2005-02-21T13:49:00.000-05:00</published><updated>2005-05-21T14:24:12.203-04:00</updated><title type='text'>In-laws, Jerry, Boxing and a pessimistic wine junky</title><content type='html'>Another weekend has gone by. Unlike most of them, this last one was filled with all kinds of excitement. First my in-laws arrived (it still sounds strange) and we had a fine dinner of &lt;A href="http://www.omahasteaks.com/"&gt;Omaha Steaks&lt;/A&gt;. I got tickets to a Jerry Seinfeld performance for them for Christmas and the four of us went to the show Friday night.&amp;nbsp; We had pretty good seats and it was very funny. Apart from a little navigation difficulties on the way there, we had a delightful time.&lt;br /&gt;&lt;br /&gt;Saturday we met them for breakfast at a local diner then hung out at home for a little while. They left early afternoon and the wife and I went to see "Million Dollar Baby". Apart from my general disliking of Eastwood's speaking voice, the movie was quite good and I can see why it's getting so much praise. A bit depressing though.&lt;br /&gt;&lt;br /&gt;Sunday consisted of brunch with the neighbor and a late afternoon trip to the local indie theatre for "Sideways". I don't think it deserves all the hype it's been getting but it was good nonetheless. Then we went to dinner at a Vietnamese place we hadn't tried yet that is conveniently right next door to the theatre. My food preference is "bland farm" but my wife has been getting me to experience some more culturally diverse cuisine. I'm getting there.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-111669985219951164?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/111669985219951164/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=111669985219951164' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/111669985219951164'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/111669985219951164'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2005/02/in-laws-jerry-boxing-and-pessimistic.html' title='In-laws, Jerry, Boxing and a pessimistic wine junky'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-111670008499260133</id><published>2005-01-08T08:13:00.000-05:00</published><updated>2005-05-21T14:28:05.000-04:00</updated><title type='text'>Junk mail, email and keeping the USPS in business</title><content type='html'>Hardly a day goes by that I don't get some kind of junk mail offer in&lt;br /&gt;my post box. Usually credit card offers. Now I greatly&lt;br /&gt;appreciate that the financial institutions recognize that I have great&lt;br /&gt;credit and can understand their desire to get a piece of my&lt;br /&gt;wallet. However, I get sick of the junk mail and I feel bad that&lt;br /&gt;the town I live in has a poor paper recycling program that forces me to&lt;br /&gt;toss the offers in the regular trash.&lt;br /&gt;&lt;br /&gt;As the internet and use of email has progressed there has been talk of&lt;br /&gt;the United States Postal Service suffering due to the decreased use of&lt;br /&gt;snail mail. Companies sending junk mail certainly don't seem to&lt;br /&gt;have slowed down. Meanwhile, the people who now use email to keep&lt;br /&gt;in touch with their friends and family probably never really wrote&lt;br /&gt;enough letters to make a significant dent in the USPS profits to begin&lt;br /&gt;with. They telephoned, so if anyone's hurting it's the phone&lt;br /&gt;companies, and I don't feel so terribly bad about that.&lt;br /&gt;&lt;br /&gt;Thanks to Andy Roony of 60 Minutes I now have a great solution that&lt;br /&gt;solves these problems. My trash can won't get as full, and I'll&lt;br /&gt;help keep the USPS in business. The best part is that it doesn't&lt;br /&gt;cost me a dime. The companies that send this crap to us really&lt;br /&gt;want us to write back to them. They have included a self&lt;br /&gt;addressed stamped envelope in the form of that "Business Reply Mail"&lt;br /&gt;(BRM) envelope. It's actually not stamped so this is where the&lt;br /&gt;keeping the USPS in business part comes in. The postage for those&lt;br /&gt;BRM envelopes is paid for by the company you are replying to but ONLY&lt;br /&gt;when it is actually used. Otherwise it's not economical to send&lt;br /&gt;junk mail. So let's use it.&lt;br /&gt;&lt;br /&gt;The process is simple. Open your junk mail envelope and find that&lt;br /&gt;BRM envelope in it. Take everything else, including the original&lt;br /&gt;envelope (which you might have to cut up into a few pieces) and place&lt;br /&gt;it back in the BRM envelope, lick it, seal it and drop it in the&lt;br /&gt;mail. That's it. Now the companies that send the junk can&lt;br /&gt;dispose of the junk and the USPS gets some more business. If you&lt;br /&gt;want, throw in some more trash you might have. You'd be surprised&lt;br /&gt;how much you can stuff into those envelopes. Also, if you so&lt;br /&gt;choose, you can leave a little note inside the returned mail telling&lt;br /&gt;them to take you off their mailing list. Perhaps we can reduce&lt;br /&gt;the junk we get while disposing of it.&lt;br /&gt;&lt;br /&gt;I'm not going to try to do the math on this, but I bet that if everyone&lt;br /&gt;who gets this stuff takes a few seconds to send it back we could do the&lt;br /&gt;USPS a real favor. Maybe the price of stamps wouldn't keep&lt;br /&gt;jumping up which just further deters us from using snail mail to send&lt;br /&gt;correspondence.&lt;br /&gt;&lt;br /&gt;Do your part! Return the trash.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-111670008499260133?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/111670008499260133/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=111670008499260133' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/111670008499260133'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/111670008499260133'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2005/01/junk-mail-email-and-keeping-usps-in.html' title='Junk mail, email and keeping the USPS in business'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-111670022355382735</id><published>2005-01-05T12:31:00.000-05:00</published><updated>2005-05-21T14:30:23.560-04:00</updated><title type='text'>New article on spaanjaars.com</title><content type='html'>I just wrote a short article entitled "&lt;A href="http://imar.spaanjaars.com/QuickDocId.aspx?QUICKDOC=337"&gt;'Re'implementing Interface Implementations: VB.NET vs. C#&lt;/A&gt;" which discusses how to implement an interface method a second time on a class that is derived from a class that already&amp;nbsp;implements the interface.&amp;nbsp; It also discusses the differences between doing this in VB.NET and C#.&lt;br /&gt;&lt;br /&gt;&lt;A href="http://imar.spaanjaars.com/QuickDocId.aspx?QUICKDOC=337"&gt;Take a look&lt;/A&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-111670022355382735?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/111670022355382735/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=111670022355382735' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/111670022355382735'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/111670022355382735'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2005/01/new-article-on-spaanjaarscom.html' title='New article on spaanjaars.com'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13073408.post-111670035576220629</id><published>2005-01-02T22:25:00.000-05:00</published><updated>2005-05-21T14:32:35.763-04:00</updated><title type='text'>Happy New Year!</title><content type='html'>Hope everyone had a pleasant new years weekend.  Nothing major happened for me.  Spent the weekend at the in-laws and celebrated Mrs. GeekDork's birthday (a week or so late).  Had no intentions of doing anything rambunctous for new years and was quite successful.  Spent it watching the newly released Seinfeld DVDs.  Finished the first season (all 5 episodes) just before midnight, watched the ball drop and went to bed at 12:02.  Woohoo.  I really don't see what all the fuss is about.  I mean, it's just another second of another day of another year... my appologies for being cynical.&lt;br /&gt;&lt;br /&gt;Spent the better part of the 1st working on my first attempt at a multi (4) layer cake.  Had never tried before and was surprisingly pleased with the outcome, though it was a smidge lopsided but tasty nonetheless.  Vanilla cake, chocolate pudding, whipped cream and strawberries.  Yum!&lt;br /&gt;&lt;br /&gt;Now the holidays are over and I must return to work after several short weeks.  Oh the humanity.&lt;br /&gt;&lt;br /&gt;Cheers!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13073408-111670035576220629?l=www.compiledthoughts.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.compiledthoughts.com/feeds/111670035576220629/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13073408&amp;postID=111670035576220629' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/111670035576220629'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13073408/posts/default/111670035576220629'/><link rel='alternate' type='text/html' href='http://www.compiledthoughts.com/2005/01/happy-new-year.html' title='Happy New Year!'/><author><name>Peter Lanoie</name><uri>http://www.blogger.com/profile/11480942345027154915</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_1ODj8s-E01o/SpfoAWkvESI/AAAAAAAAAK8/6z4OkQUZQEk/s1600-R/1f8b331ee1b89573b7632226b8e6632b.png'/></author><thr:total>0</thr:total></entry></feed>
