<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:copyright="http://blogs.law.harvard.edu/tech/rss" xmlns:image="http://purl.org/rss/1.0/modules/image/">
    <channel>
        <title>Hacky Hacky</title>
        <link>http://vijay.screamingpens.com/Default.aspx</link>
        <description>Journeys of a Cut n Paste Ninja</description>
        <language>en-AU</language>
        <copyright>Vijay Santhanam</copyright>
        <managingEditor>vijay.santhanam@gmail.com</managingEditor>
        <generator>Subtext Version 1.9.5.177</generator>
        <image>
            <title>Hacky Hacky</title>
            <url>http://vijay.screamingpens.com/images/RSS2Image.gif</url>
            <link>http://vijay.screamingpens.com/Default.aspx</link>
            <width>77</width>
            <height>60</height>
        </image>
        <item>
            <title>ReaderWriterLock(Slim) Extension Methods</title>
            <link>http://vijay.screamingpens.com/archive/2008/08/08/readerwriterlockslim-extension-methods.aspx</link>
            <description>&lt;p&gt;With the .NET framework 3.5 came a new implementation of the reader writer lock that solved many flaws of the original design. &lt;a href="http://www.bluebytesoftware.com/blog/PermaLink,guid,c4ea3d6d-190a-48f8-a677-44a438d8386b.aspx"&gt;Joe Duffy&lt;/a&gt; describes in detail what's new in ReaderWriterLockSlim, how it differs from the old version and why a new class was needed to do the same thing.&lt;/p&gt;  &lt;p&gt;In most of my applications, when I use a reader writer lock I use them &lt;strong&gt;&lt;em&gt;a lot.  &lt;/em&gt;&lt;/strong&gt;Fortunately, using the lock is straight forward:&lt;/p&gt;  &lt;div&gt;   &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: rgb(244,244,244); margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas,'Courier New',courier,monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;p&gt;var rwLock = &lt;span style="color: rgb(0,0,255)"&gt;new&lt;/span&gt; ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);&lt;br /&gt;rwLock.EnterReadLock();&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;try&lt;/span&gt; {&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;// do stuff&lt;/span&gt;  &lt;br /&gt;} &lt;span style="color: rgb(0,0,255)"&gt;catch&lt;/span&gt; (Exception ex) {&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;// handle exception&lt;/span&gt; &lt;br /&gt;} &lt;span style="color: rgb(0,0,255)"&gt;finally&lt;/span&gt; {&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;// release the lock&lt;/span&gt;     &lt;br /&gt;    rwLock.ExitReadLock(); &lt;br /&gt;}&lt;/p&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;But when you're acquiring/releasing locks a lot, your code is littered with try-catch-finally's. &lt;/p&gt;

&lt;p&gt;This isn't an earth-shattering-world-heating-climate-cooling-mass-destruction problem, but I'm a big fan of simplifying and cleaning up code where ever I can - for no other reason than the &lt;a href="http://en.wikipedia.org/wiki/KISS_principle"&gt;KISS principle&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In C# 3.0, extension methods and lambda's provide us with a great way to extend and wrap existing class behaviour. I used lambdas in continuations in my &lt;a href="http://vijay.screamingpens.com/archive/2008/05/26/actiondisposable.aspx"&gt;ActionDisposable post&lt;/a&gt; to give a collection class some public locking. &lt;/p&gt;

&lt;p&gt;With extension methods, I can extend the ReaderWriterLockSlim class itself to simplify the use of the lock.&lt;/p&gt;

&lt;div&gt;
  &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: rgb(244,244,244); margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas,'Courier New',courier,monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;p&gt;&lt;span style="color: rgb(0,0,255)"&gt;using&lt;/span&gt; System;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;namespace&lt;/span&gt; System.Threading {&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;static&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;class&lt;/span&gt; ReaderWriteLockExtensions {&lt;br /&gt;        &lt;span style="color: rgb(204,102,51)"&gt;#region&lt;/span&gt; Disposable&lt;br /&gt;&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;struct&lt;/span&gt; Disposable : IDisposable {&lt;br /&gt;            &lt;span style="color: rgb(0,0,255)"&gt;readonly&lt;/span&gt; Action action;&lt;br /&gt;&lt;br /&gt;            &lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; Disposable(Action action) {&lt;br /&gt;                &lt;span style="color: rgb(0,0,255)"&gt;this&lt;/span&gt;.action = action;&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            &lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;void&lt;/span&gt; Dispose() {&lt;br /&gt;                action();&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span style="color: rgb(204,102,51)"&gt;#endregion&lt;/span&gt;          &lt;/p&gt;&lt;p&gt;        &lt;span style="color: rgb(204,102,51)"&gt;#region&lt;/span&gt; Lock Helpers&lt;br /&gt;&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;static&lt;/span&gt; IDisposable ReadLock(&lt;span style="color: rgb(0,0,255)"&gt;this&lt;/span&gt; ReaderWriterLockSlim l) {&lt;br /&gt;            l.EnterReadLock();&lt;br /&gt;            &lt;span style="color: rgb(0,0,255)"&gt;return&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;new&lt;/span&gt; Disposable(l.ExitReadLock);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;static&lt;/span&gt; IDisposable UpgradableReadLock(&lt;span style="color: rgb(0,0,255)"&gt;this&lt;/span&gt; ReaderWriterLockSlim l) {&lt;br /&gt;            l.EnterUpgradeableReadLock();&lt;br /&gt;            &lt;span style="color: rgb(0,0,255)"&gt;return&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;new&lt;/span&gt; Disposable(l.ExitUpgradeableReadLock);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;static&lt;/span&gt; IDisposable WriteLock(&lt;span style="color: rgb(0,0,255)"&gt;this&lt;/span&gt; ReaderWriterLockSlim l) {&lt;br /&gt;            l.EnterWriteLock();&lt;br /&gt;            &lt;span style="color: rgb(0,0,255)"&gt;return&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;new&lt;/span&gt; Disposable(l.ExitWriteLock);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span style="color: rgb(204,102,51)"&gt;#endregion&lt;/span&gt;     &lt;br /&gt;    } &lt;br /&gt;}&lt;/p&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;ReadLock(), UpgradableReadLock() and WriteLock() return IDisposable, which can be used in &lt;strong&gt;&lt;em&gt;using() &lt;/em&gt;&lt;/strong&gt;blocks that automatically clean-up even when exceptions are thrown.&lt;/p&gt;

&lt;div&gt;
  &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: rgb(244,244,244); margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas,'Courier New',courier,monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;p&gt;var rwLock = &lt;span style="color: rgb(0,0,255)"&gt;new&lt;/span&gt; ReaderWriterLockSlim();&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;using&lt;/span&gt; (rwLock.ReadLock()) {&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;// do reading stuff&lt;/span&gt; &lt;/p&gt;&lt;p&gt;}&lt;/p&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;It's a little easier to read, and has certainly cleaned up our heavily locked code. &lt;/p&gt;&lt;img src="http://vijay.screamingpens.com/aggbug/16.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Vijay Santhanam</dc:creator>
            <guid>http://vijay.screamingpens.com/archive/2008/08/08/readerwriterlockslim-extension-methods.aspx</guid>
            <pubDate>Fri, 08 Aug 2008 06:28:00 GMT</pubDate>
            <wfw:comment>http://vijay.screamingpens.com/comments/16.aspx</wfw:comment>
            <comments>http://vijay.screamingpens.com/archive/2008/08/08/readerwriterlockslim-extension-methods.aspx#feedback</comments>
            <slash:comments>3</slash:comments>
            <wfw:commentRss>http://vijay.screamingpens.com/comments/commentRss/16.aspx</wfw:commentRss>
        </item>
        <item>
            <title>LINQ &amp;amp; Lambda, Part 4: Lucene.Net</title>
            <link>http://vijay.screamingpens.com/archive/2008/07/21/linq-amp-lambda-part-4-lucene.net.aspx</link>
            <description>&lt;p&gt;&lt;a href="http://en.wikipedia.org/wiki/Lucene"&gt;Lucene&lt;/a&gt; is a jewel in the open source world - its a highly scalable, fast search engine written in Java. Its class-per-class C# cousin - &lt;a href="http://incubator.apache.org/lucene.net/"&gt;Lucene.Net&lt;/a&gt; - is also a precious stone in the .NET universe. Over the years, Lucene.Net has gained considerable popularity and is used in a wide &lt;a href="http://en.wikipedia.org/w/index.php?title=Lucene&amp;amp;oldid=212350361"&gt;range of products&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.cnet.com/"&gt;C|NET&lt;/a&gt;, &lt;a href="http://www.fogcreek.com/FogBUGZ/IntrotoOnDemand.html"&gt;Fogbugz on Demand&lt;/a&gt; and &lt;a href="http://tirania.org/blog/archive/2005/May-30.html"&gt;Wikipedia&lt;/a&gt; are just a few sites that use Lucene.Net for indexing and searching their vast content. Even Microsoft has been forced to deal with a &lt;a href="http://www.joelonsoftware.com/items/2007/12/24.html"&gt;Lucene powered competitor&lt;/a&gt; Outlook extension that embarrasses the built-in search engine. &lt;/p&gt;
&lt;p&gt;It's an extremely useful tool in the belt of any software engineer. Not just for it's design and implementation of modern information retrieval theories, but for it's simple API too. &lt;/p&gt;
&lt;p&gt;From my experiences, libraries with simple concepts have simple API's. Lucene is no different because the search engine concept is very simple. A search engine is a system for finding text from a large set &lt;em&gt;&lt;strong&gt;very&lt;/strong&gt; &lt;/em&gt;quickly. &lt;/p&gt;
&lt;p&gt;At the heart of the engine is the &lt;a href="http://en.wikipedia.org/wiki/Index_(search_engine)"&gt;index&lt;/a&gt; (similar to a database table) with fields (like database columns) that contains documents (like database rows). To search one must write a query and give it to the engine to finding matching documents. The query language for a database is SQL and for Lucene it's a &lt;a href="http://incubator.apache.org/lucene.net/docs/2.1/Lucene.Net.Search.Query.html"&gt;query&lt;/a&gt; object (you can construct complex queries by composing an object graph of query instances). &lt;/p&gt;
&lt;p&gt;Search engines are super fast for finding text because documents are stored in an &lt;a href="http://en.wikipedia.org/wiki/Inverted_index"&gt;inverted index&lt;/a&gt; (where the terms of each field is tokenized, hashed and sorted at index time). &lt;/p&gt;
&lt;p&gt;In contrast to database queries, search engines can calculate relevance scores when searching. This is because they use a better querying model called the &lt;a href="http://en.wikipedia.org/wiki/Vector_space_model"&gt;vector space model&lt;/a&gt; instead of the classical boolean model. In the vector model, documents and queries are represented as vectors. The &lt;em&gt;&lt;strong&gt;similarity&lt;/strong&gt;&lt;/em&gt; between a query and any document can be calculated with simple vector operations. Documents with a higher similarity will appear higher in the results. Conversely, databases only know if rows meets the &lt;em&gt;&lt;strong&gt;where&lt;/strong&gt;&lt;/em&gt; criteria or not and cannot compute a relevance score - this true/false classification is how the boolean model got it's name.&lt;/p&gt;
&lt;p&gt;Search engines are rad!! And with Lucene any developer can easily add a search engine to their application. &lt;/p&gt;
&lt;p&gt;To satiate the rampant LINQ junkie within, I've been contributing to the &lt;a href="http://www.codeplex.com/linqtolucene"&gt;LINQ to Lucene project&lt;/a&gt; - an open source LINQ provider framework.&lt;/p&gt;
&lt;p&gt;My recent contribution to the project makes creating indexes and searching them even easier. Today, I'm going to demonstrate some features I've added so you too can easily Lucene-ify your application.&lt;/p&gt;
&lt;p&gt;A common use of Lucene in applications is to complement the database with a Lucene index for searching. LINQ to Lucene offers this functionality out of the box with LINQ to SQL from data generated classes.&lt;/p&gt;
&lt;p&gt;Let's start with the &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=06616212-0356-46A0-8DA2-EEBC53A68034&amp;amp;displaylang=en"&gt;Northwind database&lt;/a&gt;. By following Scott Gu's &lt;a href="http://weblogs.asp.net/scottgu/archive/2007/05/29/linq-to-sql-part-2-defining-our-data-model-classes.aspx"&gt;instructions&lt;/a&gt;, you can create a DBML file with generated classes from the database schema. This demonstration only needs the Customer and Order table.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://vijay.screamingpens.com/images/vijay_screamingpens_com/WindowsLiveWriter/LINQLambdaPart4LinqtoLuceneGoodness_F876/linq%20to%20sql_2.gif"&gt;&lt;img width="568" height="484" border="0" style="border: 0px none ;" alt="linq to sql" src="http://vijay.screamingpens.com/images/vijay_screamingpens_com/WindowsLiveWriter/LINQLambdaPart4LinqtoLuceneGoodness_F876/linq%20to%20sql_thumb.gif" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;The next step is to inform LINQ to Lucene which classes to index and how they are indexed using attributes. We do this extending the Customer and Order generated classes and decorating them with attributes. If you don't know how to create partial classes, see Chris Sainty's &lt;a href="http://csainty.blogspot.com/2008/01/linq-to-sql-extending-data-classes.html"&gt;post&lt;/a&gt;.&lt;/p&gt;
&lt;pre class="csharpcode"&gt;[Document]&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;partial&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Customer {&lt;br /&gt;}&lt;/pre&gt;
&lt;style type="text/css"&gt;&lt;![CDATA[

.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }]]&gt;&lt;/style&gt;
&lt;pre class="csharpcode"&gt;[Document]&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;partial&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Order {&lt;br /&gt;}&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Now we've marked these two classes as documents for indexing. The next step is to specify how each field is indexed. &lt;em&gt;But&lt;/em&gt;, there is a bit of a problem with properties in generated classes. There is &lt;em&gt;no way&lt;/em&gt; to add attributes to generated properties without spoiling the automatically generated files. &lt;/p&gt;
&lt;p&gt;Our solution to this is to add the &lt;strong&gt;&lt;em&gt;MetadataType &lt;/em&gt;&lt;/strong&gt;property on the &lt;em&gt;&lt;strong&gt;DocumentAttribute&lt;/strong&gt;&lt;/em&gt; which tells Lucene to look at another class for the field attributes it needs. Like so:&lt;/p&gt;
&lt;pre class="csharpcode"&gt;[Document(Metadatatype= typeof(CustomerMetadata))]&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;partial&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Customer {&lt;br /&gt;}&lt;/pre&gt;
&lt;style type="text/css"&gt;&lt;![CDATA[

.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }]]&gt;&lt;/style&gt;
&lt;pre class="csharpcode"&gt;[Document(Metadatatype= typeof(OrderMetadata))]&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;partial&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Order {&lt;br /&gt;}&lt;/pre&gt;
&lt;style type="text/css"&gt;&lt;![CDATA[

.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }]]&gt;&lt;/style&gt;
&lt;p&gt;Now we can create fake properties on our metadata types to specify field characteristics. The return type of the fake properties doesn't matter, only the name has to match.&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; CustomerMetadata {&lt;br /&gt;&lt;br /&gt;    [Field(FieldIndex.Tokenized, FieldStore.Yes, IsDefault = &lt;span class="kwrd"&gt;true&lt;/span&gt;)]&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt; ContactName { get; set; }&lt;br /&gt;&lt;br /&gt;    [Field(FieldIndex.Tokenized, FieldStore.Yes, IsKey= &lt;span class="kwrd"&gt;true&lt;/span&gt;)]&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt; CustomerID { get; set; }&lt;br /&gt;&lt;br /&gt;    [Field(FieldIndex.Tokenized, FieldStore.Yes)]&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt; ContactTitle { get; set; }&lt;br /&gt;&lt;br /&gt;    [Field(FieldIndex.Tokenized, FieldStore.Yes)]&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt; CompanyName { get; set; }&lt;br /&gt;}&lt;/pre&gt;
&lt;style type="text/css"&gt;&lt;![CDATA[

.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }]]&gt;&lt;/style&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; OrderMetadata {&lt;br /&gt;&lt;br /&gt;    [Field(FieldIndex.Tokenized, FieldStore.Yes, IsKey = &lt;span class="kwrd"&gt;true&lt;/span&gt;)]&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt; OrderID { get; set; }&lt;br /&gt;&lt;br /&gt;    [Field(FieldIndex.Tokenized, FieldStore.Yes, IsDefault = &lt;span class="kwrd"&gt;true&lt;/span&gt;)]&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt; CustomerID { get; set; }&lt;br /&gt;&lt;br /&gt;    [Field(FieldIndex.Tokenized, FieldStore.Yes)]&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt; ShipName { get; set; }&lt;br /&gt;&lt;br /&gt;    [Field(FieldIndex.Tokenized, FieldStore.Yes)]&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt; ShipAddress { get; set; }&lt;br /&gt;&lt;br /&gt;    [Field(FieldIndex.Tokenized, FieldStore.Yes)]&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt; ShipCity { get; set; }&lt;br /&gt;&lt;br /&gt;    [Field(FieldIndex.Tokenized, FieldStore.Yes)]&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt; ShipCountry { get; set; }&lt;br /&gt;}&lt;/pre&gt;
&lt;style type="text/css"&gt;&lt;![CDATA[

.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }]]&gt;&lt;/style&gt;
&lt;p&gt;Now we've told Lucene.Net which properties to index and how to index them.&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;The &lt;em&gt;&lt;strong&gt;FieldIndex&lt;/strong&gt;&lt;/em&gt; property indicates whether or not the field is tokenized (i.e. split into parts). By default, this is UnTokenized to save index space. &lt;/li&gt;
    &lt;li&gt;The &lt;em&gt;&lt;strong&gt;FieldStore&lt;/strong&gt;&lt;/em&gt; property tells Lucene whether or not to store the original value in the index. Again, by default, this is NO to save index space. &lt;/li&gt;
    &lt;li&gt;&lt;em&gt;&lt;strong&gt;IsKey&lt;/strong&gt;&lt;/em&gt; should be true for the fields primary key. Only one property can be marked as the key, so LINQ to SQL classes with composite keys should have a new uniquely identifying property. &lt;/li&gt;
    &lt;li&gt;&lt;em&gt;&lt;strong&gt;IsDefault&lt;/strong&gt;&lt;/em&gt; tells Lucene which field is the default field for searching. &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now we're ready to create the index.&lt;/p&gt;
&lt;p&gt;To create the index from a LINQ to SQL Data Context, we use the DatabaseIndexSet like so:&lt;/p&gt;
&lt;pre class="csharpcode"&gt;var dbi = &lt;span class="kwrd"&gt;new&lt;/span&gt; DatabaseIndexSet&amp;lt;NorthwindDataContext&amp;gt;(&lt;br /&gt;                                         @"C:\index\",                  &lt;span class="rem"&gt;// index path&lt;/span&gt;                                          &lt;span class="kwrd"&gt;&lt;br /&gt;                                         new&lt;/span&gt; NorthwindDataContext()     &lt;span class="rem"&gt;// data context instance&lt;/span&gt;                                          &lt;br /&gt;                 ); &lt;br /&gt;dbi.Write();&lt;/pre&gt;
&lt;style type="text/css"&gt;&lt;![CDATA[

.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }]]&gt;&lt;/style&gt;&lt;style type="text/css"&gt;&lt;![CDATA[

.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }]]&gt;&lt;/style&gt;
&lt;p&gt;By running this code, we'll create an index for the entire contents of the Customer and Order tables. LINQ to Lucene is smart enough to collect all the relevant data from the Northwind database, convert each row to a Lucene Document and add it to the index.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://vijay.screamingpens.com/images/vijay_screamingpens_com/WindowsLiveWriter/LINQLambdaPart4LinqtoLuceneGoodness_F876/Linq%20to%20lucene%20sample%20indexing_2.gif"&gt;&lt;img width="644" height="269" border="0" style="border-width: 0px;" alt="Linq to lucene sample indexing" src="http://vijay.screamingpens.com/images/vijay_screamingpens_com/WindowsLiveWriter/LINQLambdaPart4LinqtoLuceneGoodness_F876/Linq%20to%20lucene%20sample%20indexing_thumb.gif" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Sweet! We've got an index of the Customer and Order tables.&lt;/p&gt;
&lt;p&gt;Now we can search for Customers or Orders.&lt;/p&gt;
&lt;p&gt;Let's find all the Customers who are Marketing Managers...&lt;/p&gt;
&lt;pre class="csharpcode"&gt;var mmCustomers = from c &lt;span class="kwrd"&gt;in&lt;/span&gt; dbi.Get&amp;lt;Customer&amp;gt;()&lt;br /&gt;                      &lt;span class="kwrd"&gt;where&lt;/span&gt; c.ContactTitle == &lt;span class="str"&gt;"Marketing Manager"&lt;/span&gt;                       &lt;br /&gt;                      select c;&lt;br /&gt; &lt;br /&gt;Console.WriteLine(&lt;span class="str"&gt;"Marketing Manager Customers: Found {0}"&lt;/span&gt;, mmCustomers.Count());&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;foreach&lt;/span&gt; (var customer &lt;span class="kwrd"&gt;in&lt;/span&gt; mmCustomers) {&lt;br /&gt;    Console.WriteLine(customer.ContactName);&lt;br /&gt;}&lt;/pre&gt;
&lt;style type="text/css"&gt;&lt;![CDATA[

.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }]]&gt;&lt;/style&gt;
&lt;p&gt;&lt;a href="http://vijay.screamingpens.com/images/vijay_screamingpens_com/WindowsLiveWriter/LINQLambdaPart4LinqtoLuceneGoodness_F876/Linq%20to%20lucene%20sample%20marketing%20search_2.gif"&gt;&lt;img width="681" height="272" border="0" style="border-width: 0px;" alt="Linq to lucene sample marketing search" src="http://vijay.screamingpens.com/images/vijay_screamingpens_com/WindowsLiveWriter/LINQLambdaPart4LinqtoLuceneGoodness_F876/Linq%20to%20lucene%20sample%20marketing%20search_thumb.gif" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;This very simple example demonstrates the query equality operator, but many other types of query are possible (including wildcards, prefixes, proximities). You can find more ways to query on the &lt;a href="http://www.codeplex.com/linqtolucene"&gt;LINQ to Lucene homepage&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In future posts, I'll demonstrate more complex query examples and how to supply custom formatters for properties. &lt;/p&gt;
&lt;p&gt;To see the source of LINQ to Lucene, you can get the &lt;a href="http://www.codeplex.com/linqtolucene/SourceControl/ListDownloadableCommits.aspx"&gt;latest release&lt;/a&gt;. The sample project from this post is available for download &lt;a href="http://cid-ae88a0a375756b49.skydrive.live.com/self.aspx/Public/Lucene.Linq.Sample.zip"&gt;here&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;NOTE: The sample project uses the Northwind database as a data source. Northwind can be downloaded and installed to your SQL Server instance from &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=06616212-0356-46A0-8DA2-EEBC53A68034&amp;amp;displaylang=en"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt; &lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fvijay.screamingpens.com%2farchive%2f2008%2f07%2f21%2flinq-amp-lambda-part-4-lucene.net.aspx"&gt;&lt;img border="0" alt="kick it on DotNetKicks.com" src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fvijay.screamingpens.com%2farchive%2f2008%2f07%2f21%2flinq-amp-lambda-part-4-lucene.net.aspx" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;img src="http://vijay.screamingpens.com/aggbug/15.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Vijay Santhanam</dc:creator>
            <guid>http://vijay.screamingpens.com/archive/2008/07/21/linq-amp-lambda-part-4-lucene.net.aspx</guid>
            <pubDate>Sun, 20 Jul 2008 15:51:26 GMT</pubDate>
            <wfw:comment>http://vijay.screamingpens.com/comments/15.aspx</wfw:comment>
            <comments>http://vijay.screamingpens.com/archive/2008/07/21/linq-amp-lambda-part-4-lucene.net.aspx#feedback</comments>
            <slash:comments>8</slash:comments>
            <wfw:commentRss>http://vijay.screamingpens.com/comments/commentRss/15.aspx</wfw:commentRss>
        </item>
        <item>
            <title>LINQ &amp;amp; Lambda, Part 3: Html Agility Pack to LINQ to XML Converter</title>
            <link>http://vijay.screamingpens.com/archive/2008/05/26/linq-amp-lambda-part-3-html-agility-pack-to-linq.aspx</link>
            <description>&lt;p&gt; &lt;/p&gt;
&lt;p&gt;The &lt;a href="http://www.codeplex.com/htmlagilitypack/"&gt;Html Agility Pack&lt;/a&gt; brings flexible, versatile html parsing onto the .NET platform. It's a great toolkit for scraping websites that don't offer formal, documented APIs. &lt;/p&gt;
&lt;p&gt;Under the hood, the agility pack has it's own parser that's deftly designed to parse malformed HTML in all it's nasty real-life forms. &lt;/p&gt;
&lt;p&gt;For querying and traversing a parsed document, the pack offers a in-memory object graph, XPath and XSLT. Today I'd like to add a LINQ to XML converter for extra HTML agility in this new .NET 3.5 post-MIX '08 world.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Collections.Generic;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Linq;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Text;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Xml.Linq;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.IO;&lt;/pre&gt;
&lt;pre class="alt"&gt; &lt;/pre&gt;
&lt;pre&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; HtmlAgilityPack&lt;/pre&gt;
&lt;pre class="alt"&gt;{&lt;/pre&gt;
&lt;pre&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; HtmlDocumentExtensions&lt;/pre&gt;
&lt;pre class="alt"&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; XDocument ToXDocument(&lt;span class="kwrd"&gt;this&lt;/span&gt; HtmlDocument document)&lt;/pre&gt;
&lt;pre class="alt"&gt;        {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class="kwrd"&gt;using&lt;/span&gt; (StringWriter sw = &lt;span class="kwrd"&gt;new&lt;/span&gt; StringWriter())&lt;/pre&gt;
&lt;pre class="alt"&gt;            {&lt;/pre&gt;
&lt;pre&gt;                document.OptionOutputAsXml = &lt;span class="kwrd"&gt;true&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class="alt"&gt;                document.Save(sw);&lt;/pre&gt;
&lt;pre&gt;                &lt;span class="kwrd"&gt;return&lt;/span&gt; XDocument.Parse(sw.GetStringBuilder().ToString());&lt;/pre&gt;
&lt;pre class="alt"&gt;            }&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class="alt"&gt;    }&lt;/pre&gt;
&lt;pre&gt;}&lt;/pre&gt;
&lt;/div&gt;
&lt;style type="text/css"&gt;&lt;![CDATA[





.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }]]&gt;&lt;/style&gt;
&lt;p&gt;For a demonstration on how to use this, I'm going to partially solve a scraping problem I came across a few days ago. Basically, I needed to find all the images on a webpage, order them by descending size, and list them to the user for their selection. Their choice would be used to generate a thumbnail. Social content sites like &lt;a href="http://www.digg.com"&gt;Digg&lt;/a&gt; and &lt;a href="http://www.mixx.com"&gt;Mixx&lt;/a&gt; do something similar, but seem to download the top 10 biggest images, thumbnail them anyway and let the user choose. In the following example, I'm going to simply find all the images in the right order and let the reader do the thumbnailing :)&lt;/p&gt;
&lt;p&gt;The first step is to download a page and convert it's HtmlDocument object graph into an XDocument.&lt;/p&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;HtmlWeb hw = &lt;span class="kwrd"&gt;new&lt;/span&gt; HtmlWeb();&lt;/pre&gt;
&lt;pre&gt;&lt;span class="kwrd"&gt;string&lt;/span&gt; url = &lt;span class="str"&gt;@"http://www.nytimes.com/2008/05/18/us/politics/18memoirs.html?hp"&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class="alt"&gt;Uri uri = &lt;span class="kwrd"&gt;new&lt;/span&gt; Uri(url);&lt;/pre&gt;
&lt;pre&gt; &lt;/pre&gt;
&lt;pre class="alt"&gt;HtmlDocument doc = hw.Load(url);&lt;/pre&gt;
&lt;pre&gt;var xdoc = doc.ToXDocument();&lt;/pre&gt;
&lt;/div&gt;
&lt;style type="text/css"&gt;&lt;![CDATA[
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }]]&gt;&lt;/style&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Now we can find all the &lt;a href="http://www.w3schools.com/tags/tag_IMG.asp"&gt;image tags&lt;/a&gt; with a simple LINQ expression.&lt;/p&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;var imgs =&lt;/pre&gt;
&lt;pre&gt;        from el &lt;span class="kwrd"&gt;in&lt;/span&gt; xdoc.Descendants()&lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;where&lt;/span&gt; el.Name.LocalName == &lt;span class="str"&gt;"img"&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;        select &lt;/pre&gt;
&lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;new&lt;/span&gt; { &lt;/pre&gt;
&lt;pre&gt;            Src = el.Attribute(XName.Get(&lt;span class="str"&gt;"src"&lt;/span&gt;)).Value,&lt;/pre&gt;
&lt;pre class="alt"&gt;        };&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;The last step is to order them by descending size, but there's a couple of things to consider when reading the "width" and "height" from an image XElement.&lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;"width" and "height" may not exist. These attributes aren't mandatory. &lt;/li&gt;
    &lt;li&gt;"width" and "height" may be expressed in percentages.&lt;/li&gt;
    &lt;li&gt;XElement.Attribute(XName.Get("width")).Value will throw a NullRefereceException if the attribute doesn't exist.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Every raster image has a width and height, even if the image tag doesn't. If the size cannot be seen on the tag, we could download and open the image to find out it's true height/width. A fast way to do this would be read the image header, but this post isn't about the &lt;em&gt;Image&lt;/em&gt; class or reading images - just LINQ to HTML. For now, I'm going to create a default width and height of 0.&lt;/p&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;XName widthAttribute = XName.Get(&lt;span class="str"&gt;"width"&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;XName heightAttribute = XName.Get(&lt;span class="str"&gt;"height"&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class="alt"&gt;XName srcAttribute = XName.Get(&lt;span class="str"&gt;"src"&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;XAttribute defaultHeight = &lt;span class="kwrd"&gt;new&lt;/span&gt; XAttribute(heightAttribute, &lt;span class="str"&gt;"0"&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class="alt"&gt;XAttribute defaultWidth = &lt;span class="kwrd"&gt;new&lt;/span&gt; XAttribute(widthAttribute, &lt;span class="str"&gt;"0"&lt;/span&gt;);&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Now we can read the width and height in the LINQ expression allowing for defaults, and adding a hack for sizes expressed in percentages.&lt;/p&gt;
&lt;pre class="csharpcode"&gt;var imgs =&lt;br /&gt;        from el &lt;span class="kwrd"&gt;in&lt;/span&gt; xdoc.Descendants()&lt;br /&gt;        let width = Int32.Parse((el.Attribute(widthAttribute) ?? defaultWidth).Value.TrimEnd(&lt;span class="str"&gt;'%'&lt;/span&gt;))&lt;br /&gt;        let height = Int32.Parse((el.Attribute(heightAttribute) ?? defaultHeight).Value.TrimEnd(&lt;span class="str"&gt;'%'&lt;/span&gt;))&lt;br /&gt;        let metric = Math.Sqrt(width * height)&lt;br /&gt;        &lt;span class="kwrd"&gt;where&lt;/span&gt; el.Name.LocalName == &lt;span class="str"&gt;"img"&lt;/span&gt;         orderby metric descending         select          &lt;span class="kwrd"&gt;new&lt;/span&gt; { &lt;br /&gt;            Src = el.Attribute(srcAttribute).Value,&lt;br /&gt;            Width = width,&lt;br /&gt;            Height = height&lt;br /&gt;        };&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;
&lt;style type="text/css"&gt;&lt;![CDATA[
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }]]&gt;&lt;/style&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;foreach&lt;/span&gt; (var image &lt;span class="kwrd"&gt;in&lt;/span&gt; imgs)&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;    Console.WriteLine(&lt;span class="str"&gt;"{0} Size: {1}x{2}"&lt;/span&gt;, &lt;/pre&gt;
&lt;pre&gt;        image.Src, &lt;/pre&gt;
&lt;pre class="alt"&gt;        image.Width, &lt;/pre&gt;
&lt;pre&gt;        image.Height);&lt;/pre&gt;
&lt;pre class="alt"&gt;}&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt; &lt;/p&gt;
&lt;style type="text/css"&gt;&lt;![CDATA[
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }]]&gt;&lt;/style&gt;
&lt;p&gt;Hey presto! The image URLs get written to the console in the right order. The output for the new york times article looks like this:&lt;/p&gt;
&lt;table border="1"&gt;
    &lt;tbody&gt;
        &lt;tr&gt;
            &lt;td&gt;
            &lt;pre&gt;Found 26 images&lt;br /&gt;&lt;br /&gt;http://graphics7.nytimes.com/images/2008/05/18/us/18mem.span.jpg Size: 600x350&lt;br /&gt;http://graphics7.nytimes.com/adx/images/ADS/14/60/ad.146024/sf.gif Size: 300x250&lt;br /&gt;http://graphics7.nytimes.com/images/2008/05/17/us/18memoir_190.jpg Size: 190x285&lt;br /&gt;http://graphics7.nytimes.com/ads/marketing/mm08/opinion_033108.jpg Size: 334x105&lt;br /&gt;http://graphics7.nytimes.com/ads/marketing/mm08/opinion_052608.jpg Size: 334x105&lt;br /&gt;http://graphics8.nytimes.com/images/2008/05/25/opinion/25moth_glanville.jpg Size: 151x151&lt;br /&gt;http://graphics8.nytimes.com/images/2008/05/25/weekinreview/25moth_wong.jpg Size: 151x151&lt;br /&gt;http://graphics8.nytimes.com/images/2008/05/23/fashion/25moth-brain1.ready.jpg Size: 151x151&lt;br /&gt;http://graphics8.nytimes.com/images/2008/05/25/opinion/25moth_classic.gif Size:&lt;br /&gt;151x151&lt;br /&gt;http://graphics8.nytimes.com/images/2008/05/25/nyregion/thecity/25moth_crime.jpg Size: 151x151&lt;br /&gt;http://graphics8.nytimes.com/images/2008/05/25/travel/25moth-trail.jpg Size: 151x151&lt;br /&gt;http://graphics7.nytimes.com/images/blogs/thecaucus/thecaucus75.jpg Size: 75x75&lt;br /&gt;http://graphics7.nytimes.com/ads/marketing/mm07/nyt-logo.png Size: 151x26&lt;br /&gt;http://graphics7.nytimes.com/ads/marketing/mm07/nyt-logo.png Size: 151x26&lt;br /&gt;http://graphics7.nytimes.com/ads/marketing/mm07/vertical_opinion.gif Size: 145x23&lt;br /&gt;http://graphics7.nytimes.com/ads/marketing/mm07/vertical_opinion.gif Size: 145x23&lt;br /&gt;http://up.nytimes.com/?d=0//&amp;amp;t=2&amp;amp;s=0&amp;amp;ui=&amp;amp;r=&amp;amp;u= Size: 3x1&lt;br /&gt;/adx/bin/clientside/7e2e2078Q2FZkQ3F3VQ7BpQ27!l6c6L7cQ7BQ7Bpp82Q27Vp Size: 3x1&lt;br /&gt;http://wt.o.nytimes.com/dcsym57yw10000s1s8g0boozt_9t1x/njs.gif?js=No&amp;amp;WT.tv=1.0.7 Size: 1x1&lt;br /&gt;http://graphics7.nytimes.com/ads/ameriprise/AMP_logo_88x31.gif Size: 0x0&lt;br /&gt;http://graphics7.nytimes.com/images/misc/nytlogo153x23.gif Size: 0x0&lt;br /&gt;http://politics.nytimes.com/images/section/politics/elections/2008.gif Size: 0x0&lt;br /&gt;http://graphics7.nytimes.com/adx/images/ADS/16/69/ad.166980/728x90_T_logo.gif Size: 0x0&lt;br /&gt;http://graphics7.nytimes.com/adx/images/ADS/16/95/ad.169529/youngheart_88x31_8.gif Size: 0x0&lt;br /&gt;http://graphics7.nytimes.com/adx/images/ADS/16/01/ad.160192/TMAG_86x60.gif Size: 0x0&lt;br /&gt;http://graphics7.nytimes.com/ads/blank.gif Size: 0x0&lt;/pre&gt;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Some of my assumptions above may seem less than ideal, but remember that it's good practice to include the width and height in the image tag so the browser knows how much visual space to leave while the page loads. For any well designed page this approach works nicely.&lt;/p&gt;
&lt;p&gt;Another neat use for LINQ :)&lt;/p&gt;
&lt;p&gt;UPDATE: you can download the code with my modifications and this sample from &lt;a href="http://cid-ae88a0a375756b49.skydrive.live.com/self.aspx/Public/HtmlAgilityPack.zip"&gt;here&lt;/a&gt;.&lt;br /&gt;
&lt;/p&gt;
&lt;p&gt; &lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fvijay.screamingpens.com%2farchive%2f2008%2f05%2f26%2flinq-amp-lambda-part-3-html-agility-pack-to-linq.aspx"&gt;&lt;img border="0" alt="kick it on DotNetKicks.com" src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fvijay.screamingpens.com%2farchive%2f2008%2f05%2f26%2flinq-amp-lambda-part-3-html-agility-pack-to-linq.aspx" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;img src="http://vijay.screamingpens.com/aggbug/12.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Vijay Santhanam</dc:creator>
            <guid>http://vijay.screamingpens.com/archive/2008/05/26/linq-amp-lambda-part-3-html-agility-pack-to-linq.aspx</guid>
            <pubDate>Mon, 26 May 2008 06:03:12 GMT</pubDate>
            <wfw:comment>http://vijay.screamingpens.com/comments/12.aspx</wfw:comment>
            <comments>http://vijay.screamingpens.com/archive/2008/05/26/linq-amp-lambda-part-3-html-agility-pack-to-linq.aspx#feedback</comments>
            <slash:comments>2</slash:comments>
            <wfw:commentRss>http://vijay.screamingpens.com/comments/commentRss/12.aspx</wfw:commentRss>
        </item>
        <item>
            <title>ActionDisposable</title>
            <link>http://vijay.screamingpens.com/archive/2008/05/26/actiondisposable.aspx</link>
            <description>&lt;p&gt;I borrowed this class from the Wes Dyer's &lt;a href="http://blogs.msdn.com/wesdyer/archive/2007/02/23/linq-to-ascii-art.aspx"&gt;LINQ to ASCII Art&lt;/a&gt; post. It's a great way to return IDisposable from a method without creating a specialized class.&lt;/p&gt;  &lt;div class="csharpcode"&gt;   &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Collections.Generic;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Linq;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Text;&lt;/pre&gt;

  &lt;pre class="alt"&gt; &lt;/pre&gt;

  &lt;pre&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; System {&lt;/pre&gt;

  &lt;pre class="alt"&gt; &lt;/pre&gt;

  &lt;pre&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; ActionDisposable: IDisposable {&lt;/pre&gt;

  &lt;pre class="alt"&gt; &lt;/pre&gt;

  &lt;pre&gt;        Action action;&lt;/pre&gt;

  &lt;pre class="alt"&gt; &lt;/pre&gt;

  &lt;pre&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; ActionDisposable(Action action) {&lt;/pre&gt;

  &lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;this&lt;/span&gt;.action = action;&lt;/pre&gt;

  &lt;pre&gt;        }&lt;/pre&gt;

  &lt;pre class="alt"&gt; &lt;/pre&gt;

  &lt;pre&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Dispose() {&lt;/pre&gt;

  &lt;pre class="alt"&gt;            action();&lt;/pre&gt;

  &lt;pre&gt;        }&lt;/pre&gt;

  &lt;pre class="alt"&gt; &lt;/pre&gt;

  &lt;pre&gt;    }&lt;/pre&gt;

  &lt;pre class="alt"&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;Wes uses ActionDisposable casually to reset Console properties. My example to demonstrate this class will be similar to Eilon Lipton's solution to &lt;a href="http://weblogs.asp.net/leftslipper/archive/2008/03/31/mvc-locking-the-routecollection.aspx"&gt;locking a collection&lt;/a&gt;, expect I'll use ActionDisposable instead of specialized ReadLockDisposable and WriteLockDisposable.&lt;/p&gt;

&lt;div class="csharpcode"&gt;
  &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; SingletonSafeCollection&amp;lt;T&amp;gt;: Collection&amp;lt;T&amp;gt;&lt;/pre&gt;

  &lt;pre&gt;{&lt;/pre&gt;

  &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; SingletonSafeCollection&amp;lt;T&amp;gt; instance = &lt;span class="kwrd"&gt;new&lt;/span&gt; SingletonSafeCollection&amp;lt;T&amp;gt;();&lt;/pre&gt;

  &lt;pre&gt; &lt;/pre&gt;

  &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; SingletonSafeCollection&amp;lt;T&amp;gt; Instance {&lt;/pre&gt;

  &lt;pre&gt;        get&lt;/pre&gt;

  &lt;pre class="alt"&gt;        {&lt;/pre&gt;

  &lt;pre&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; instance;&lt;/pre&gt;

  &lt;pre class="alt"&gt;        }&lt;/pre&gt;

  &lt;pre&gt;    }&lt;/pre&gt;

  &lt;pre class="alt"&gt; &lt;/pre&gt;

  &lt;pre&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; ReaderWriterLockSlim rwLock = &lt;span class="kwrd"&gt;new&lt;/span&gt; ReaderWriterLockSlim();&lt;/pre&gt;

  &lt;pre class="alt"&gt; &lt;/pre&gt;

  &lt;pre&gt;    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;Acquires a read lock for reading the collection&amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;    &lt;span class="rem"&gt;/// &amp;lt;returns&amp;gt;Disposable object that releases the read lock&amp;lt;/returns&amp;gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; IDisposable GetReadLock()&lt;/pre&gt;

  &lt;pre class="alt"&gt;    {&lt;/pre&gt;

  &lt;pre&gt;        rwLock.EnterReadLock();&lt;/pre&gt;

  &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ActionDisposable(rwLock.ExitReadLock);&lt;/pre&gt;

  &lt;pre&gt;    }&lt;/pre&gt;

  &lt;pre class="alt"&gt; &lt;/pre&gt;

  &lt;pre&gt;    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;Acquires a write lock for writing the collection&amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;    &lt;span class="rem"&gt;/// &amp;lt;returns&amp;gt;Disposable object that releases the write lock&amp;lt;/returns&amp;gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; IDisposable GetWriteLock()&lt;/pre&gt;

  &lt;pre class="alt"&gt;    {&lt;/pre&gt;

  &lt;pre&gt;        rwLock.EnterWriteLock();&lt;/pre&gt;

  &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ActionDisposable(rwLock.ExitWriteLock);&lt;/pre&gt;

  &lt;pre&gt;    }&lt;/pre&gt;

  &lt;pre class="alt"&gt; &lt;/pre&gt;

  &lt;pre&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;&lt;style type="text/css"&gt;&lt;![CDATA[

.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }]]&gt;&lt;/style&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;Now I can use the SingletonSafeCollection&amp;lt;T&amp;gt; anywhere in my code with guarantees that when I one takes a read lock, no one will be writing to the collection and when one takes a write lock, no one will be writing to the collection. &lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;div class="csharpcode"&gt;
  &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Main(&lt;span class="kwrd"&gt;string&lt;/span&gt;[] args)&lt;/pre&gt;

  &lt;pre&gt;{&lt;/pre&gt;

  &lt;pre class="alt"&gt;    SingletonSafeCollection&amp;lt;&lt;span class="kwrd"&gt;int&lt;/span&gt;&amp;gt; numbers = SingletonSafeCollection&amp;lt;&lt;span class="kwrd"&gt;int&lt;/span&gt;&amp;gt;.Instance;&lt;/pre&gt;

  &lt;pre&gt;    &lt;span class="kwrd"&gt;using&lt;/span&gt; (numbers.GetWriteLock())&lt;/pre&gt;

  &lt;pre class="alt"&gt;    {&lt;/pre&gt;

  &lt;pre&gt;        &lt;span class="rem"&gt;// safe to write with a guarentee no one is reading or modifying the collection (except this thread)&lt;/span&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;        numbers.Add(1212);&lt;/pre&gt;

  &lt;pre&gt;    }&lt;/pre&gt;

  &lt;pre class="alt"&gt; &lt;/pre&gt;

  &lt;pre&gt;    &lt;span class="kwrd"&gt;using&lt;/span&gt; (numbers.GetReadLock())&lt;/pre&gt;

  &lt;pre class="alt"&gt;    {&lt;/pre&gt;

  &lt;pre&gt;        &lt;span class="rem"&gt;// safe to read the list with a guarentee no one is modifying the collection&lt;/span&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;        numbers.ToList().ForEach(i =&amp;gt; Console.WriteLine(i));&lt;/pre&gt;

  &lt;pre&gt;    }&lt;/pre&gt;

  &lt;pre class="alt"&gt; &lt;/pre&gt;

  &lt;pre&gt;    Console.ReadLine();&lt;/pre&gt;

  &lt;pre class="alt"&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;&lt;style type="text/css"&gt;&lt;![CDATA[
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }]]&gt;&lt;/style&gt;&lt;img src="http://vijay.screamingpens.com/aggbug/11.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Vijay Santhanam</dc:creator>
            <guid>http://vijay.screamingpens.com/archive/2008/05/26/actiondisposable.aspx</guid>
            <pubDate>Mon, 26 May 2008 04:32:17 GMT</pubDate>
            <wfw:comment>http://vijay.screamingpens.com/comments/11.aspx</wfw:comment>
            <comments>http://vijay.screamingpens.com/archive/2008/05/26/actiondisposable.aspx#feedback</comments>
            <wfw:commentRss>http://vijay.screamingpens.com/comments/commentRss/11.aspx</wfw:commentRss>
        </item>
        <item>
            <title>LINQ &amp;amp; Lambda, Part 1: iTunes XML Querying</title>
            <link>http://vijay.screamingpens.com/archive/2008/05/05/linq-amp-lambda-part-1-itunes-xml-querying.aspx</link>
            <description>&lt;p&gt;Today I was curious what my friend's favourite artists were. Rather than just ask him and give away any surprise of this years birthday present, I decided to sneakily scrape his iTunes library. He has a wide taste in music and buys a lot of it, so he's a great source of new music. His iTunes library is filled with interesting artists, songs and compilations. On the other hand, he's in the industry and collects a lot of amateur music. When looking for an ideal birthday gift idea in his iTunes library, I'll need to consider how much he plays any song.&lt;/p&gt;
&lt;p&gt;iTunes keeps it's music metadata in an &lt;a href="http://www.xml.com/pub/a/2004/11/03/itunes.html"&gt;XML file&lt;/a&gt; for decorating music files with other metadata not supported in ID3 tags. &lt;/p&gt;
&lt;p&gt;Using LINQ, there are two ways I could query this data:-&lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;Use &lt;a href="http://msdn.microsoft.com/en-us/library/bb308960.aspx"&gt;LINQ to XML&lt;/a&gt;.&lt;/li&gt;
    &lt;li&gt;Convert the DTD to XSD, generate proxy classes using &lt;a href="http://www.hanselman.com/blog/LINQToEverythingLINQToXSDAddsMoreLINQiness.aspx"&gt;LINQ to XSD&lt;/a&gt; and then query the loaded file with &lt;a href="http://msdn.microsoft.com/en-us/library/bb397919.aspx"&gt;LINQ to Objects&lt;/a&gt;. &lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I &lt;strong&gt;*need*&lt;/strong&gt; my LINQ &amp;amp; Lambda fix - now - so I'm going to the take the fast option numero uno. If anyone is interested in seeing &lt;em&gt;LINQ to XSD&lt;/em&gt; in action, let me know in the comments.&lt;/p&gt;
&lt;p&gt;Niel Bornstein's article on &lt;a href="http://www.xml.com/pub/a/2004/11/03/itunes.html"&gt;hacking the iTunes XML&lt;/a&gt; describes the DTD clearly. Even though his article is old, the key-value pair structure allows for the addition of new properties in newer iTunes versions. &lt;/p&gt;
&lt;p&gt;If you've at least seen some XML before, simply perusing the file is enough to understand the simple format.&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;On Windows, you can find the library XML file in &lt;em&gt;My Documents\My Music\iTunes\iTunes Music Library.XML&lt;/em&gt; &lt;/li&gt;
    &lt;li&gt;On OS X, it's in &lt;em&gt;~/Music/iTunes/iTunes Music Library.XML&lt;/em&gt; &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Basically, the document root is a &lt;em&gt;plist &lt;/em&gt;tag split up into three sections - header, track info and playlist info. Each section is within a &lt;em&gt;dict &lt;/em&gt;tag, and each entity within the Track and Playlist sections are contained within &lt;em&gt;dict&lt;/em&gt; tags.&lt;/p&gt;
&lt;p&gt;The XML element for a track looks like :-&lt;/p&gt;
&lt;div style="border: 1px solid gray; margin: 20px 0px 10px; padding: 4px; overflow: auto; font-size: 8pt; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"&gt;
&lt;div style="border-style: none; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   1:&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;839&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   2:&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;dict&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   3:&lt;/span&gt;   &lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;Track ID&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;integer&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;839&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;integer&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   4:&lt;/span&gt;   &lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;Name&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;string&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;Sweet Georgia Brown&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;string&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   5:&lt;/span&gt;   &lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;Artist&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;string&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;Count Basie &amp;amp; His Orchestra&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;string&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   6:&lt;/span&gt;   &lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;Composer&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;string&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;Bernie/Pinkard/Casey&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;string&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   7:&lt;/span&gt;   &lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;Album&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;string&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;Prime Time&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;string&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   8:&lt;/span&gt;   &lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;Genre&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;string&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;Jazz&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;string&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   9:&lt;/span&gt;   &lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;Kind&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;string&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;Protected AAC audio file&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;string&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  10:&lt;/span&gt;   &lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;Size&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;integer&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;3771502&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;integer&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  11:&lt;/span&gt;   &lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;Total Time&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;integer&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;219173&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;integer&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  12:&lt;/span&gt;   &lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;Disc Number&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;integer&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;1&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;integer&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  13:&lt;/span&gt;   &lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;Disc Count&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;integer&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;1&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;integer&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  14:&lt;/span&gt;   &lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;Track Number&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;integer&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;3&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;integer&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  15:&lt;/span&gt;   &lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;Track Count&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;integer&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;8&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;integer&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  16:&lt;/span&gt;   &lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;Year&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;integer&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;1977&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;integer&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  17:&lt;/span&gt;   &lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;Date Modified&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;date&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;2004-06-16T18:10:55Z&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;date&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  18:&lt;/span&gt;   &lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;Date Added&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;date&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;2004-06-16T18:08:31Z&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;date&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  19:&lt;/span&gt;   &lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;Bit Rate&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;integer&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;128&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;integer&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  20:&lt;/span&gt;   &lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;Sample Rate&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;integer&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;44100&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;integer&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  21:&lt;/span&gt;   &lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;Play Count&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;integer&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;3&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;integer&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  22:&lt;/span&gt;   &lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;Play Date&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;integer&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;-1119376103&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;integer&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  23:&lt;/span&gt;   &lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;Play Date UTC&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;date&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;2004-08-17T16:39:53Z&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;date&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  24:&lt;/span&gt;   &lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;Rating&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;integer&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;100&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;integer&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  25:&lt;/span&gt;   &lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;Artwork Count&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;integer&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;1&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;integer&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  26:&lt;/span&gt;   &lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;File Type&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;integer&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;1295274016&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;integer&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  27:&lt;/span&gt;   &lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;File Creator&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;integer&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;1752133483&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;integer&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  28:&lt;/span&gt;   &lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;Location&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;string&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;file://localhost/Users/niel/Music/music.mp4&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;string&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  29:&lt;/span&gt;   &lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;File Folder Count&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;integer&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;4&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;integer&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  30:&lt;/span&gt;   &lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;Library Folder Count&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;key&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;integer&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;1&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;integer&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  31:&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;dict&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;To construct my query, I broke my goal into three tasks:&lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;Find the collection of tracks.&lt;/li&gt;
    &lt;li&gt;For each song, find the play count and artist name.&lt;/li&gt;
    &lt;li&gt;Descendingly sort the song list by play count.&lt;/li&gt;
    &lt;li&gt;Select any artist only once.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And here's the code to write out my friends' favourite artists in descending order of popularity.&lt;/p&gt;
&lt;div style="border: 1px solid gray; margin: 20px 0px 10px; padding: 4px; overflow: auto; font-size: 8pt; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"&gt;
&lt;div style="border-style: none; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   1:&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;using&lt;/span&gt; System;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   2:&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;using&lt;/span&gt; System.IO;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   3:&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;using&lt;/span&gt; System.Collections.Generic;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   4:&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;using&lt;/span&gt; System.Linq;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   5:&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;using&lt;/span&gt; System.Text;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   6:&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;using&lt;/span&gt; System.Xml.Linq;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   7:&lt;/span&gt;  &lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   8:&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;namespace&lt;/span&gt; iTunesXmlParser {&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;   9:&lt;/span&gt;    &lt;span style="color: rgb(0, 0, 255);"&gt;class&lt;/span&gt; Program {&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  10:&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  11:&lt;/span&gt;  &lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  12:&lt;/span&gt;        &lt;span style="color: rgb(0, 0, 255);"&gt;static&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;void&lt;/span&gt; Main(&lt;span style="color: rgb(0, 0, 255);"&gt;string&lt;/span&gt;[] args) {&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  13:&lt;/span&gt;                string xmlFile = args[1];&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  14:&lt;/span&gt;                &lt;span style="color: rgb(0, 0, 255);"&gt;using&lt;/span&gt; (var sr = &lt;span style="color: rgb(0, 0, 255);"&gt;new&lt;/span&gt; StreamReader(xmlFile)) {&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  15:&lt;/span&gt;                    var doc = XDocument.Load(sr);&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  16:&lt;/span&gt;  &lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  17:&lt;/span&gt;                    &lt;span style="color: rgb(0, 128, 0);"&gt;// find the tracks dictionary&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  18:&lt;/span&gt;                    XElement tracksDictionary = (from element &lt;span style="color: rgb(0, 0, 255);"&gt;in&lt;/span&gt; doc.Descendants()&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  19:&lt;/span&gt;                                                 &lt;span style="color: rgb(0, 0, 255);"&gt;where&lt;/span&gt; element.Value.Equals(&lt;span style="color: rgb(0, 96, 128);"&gt;"Tracks"&lt;/span&gt;)&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  20:&lt;/span&gt;                                                 select element).First().NextNode &lt;span style="color: rgb(0, 0, 255);"&gt;as&lt;/span&gt; XElement;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  21:&lt;/span&gt;  &lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  22:&lt;/span&gt;                    &lt;span style="color: rgb(0, 128, 0);"&gt;// get all distinct track artist names ordered descendingly by track play count&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  23:&lt;/span&gt;                    &lt;span style="color: rgb(0, 128, 0);"&gt;// NOTE: if no play count exists for a track, the track is assumed to have 0 plays&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  24:&lt;/span&gt;  &lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  25:&lt;/span&gt;                    List&amp;lt;&lt;span style="color: rgb(0, 0, 255);"&gt;string&lt;/span&gt;&amp;gt; artistNames = (from el &lt;span style="color: rgb(0, 0, 255);"&gt;in&lt;/span&gt; tracksDictionary.Descendants()&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  26:&lt;/span&gt;                                   let playCountValues = (from trackField &lt;span style="color: rgb(0, 0, 255);"&gt;in&lt;/span&gt; el.Descendants()&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  27:&lt;/span&gt;                                                          &lt;span style="color: rgb(0, 0, 255);"&gt;where&lt;/span&gt; trackField.Value == &lt;span style="color: rgb(0, 96, 128);"&gt;"Play Count"&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  28:&lt;/span&gt;                                                          select (trackField.NextNode &lt;span style="color: rgb(0, 0, 255);"&gt;as&lt;/span&gt; XElement))&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  29:&lt;/span&gt;                                   let artistValues = (from trackField &lt;span style="color: rgb(0, 0, 255);"&gt;in&lt;/span&gt; el.Descendants()&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  30:&lt;/span&gt;                                                          &lt;span style="color: rgb(0, 0, 255);"&gt;where&lt;/span&gt; trackField.Value == &lt;span style="color: rgb(0, 96, 128);"&gt;"Artist"&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  31:&lt;/span&gt;                                                          select (trackField.NextNode &lt;span style="color: rgb(0, 0, 255);"&gt;as&lt;/span&gt; XElement))&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  32:&lt;/span&gt;                                   &lt;span style="color: rgb(0, 0, 255);"&gt;where&lt;/span&gt; &lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  33:&lt;/span&gt;                                   el.Name.LocalName == &lt;span style="color: rgb(0, 96, 128);"&gt;"dict"&lt;/span&gt; &lt;span style="color: rgb(0, 128, 0);"&gt;// find the track key-value pair property set&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  34:&lt;/span&gt;                                   &amp;amp;&amp;amp; artistValues.Count() &amp;gt; 0 &lt;span style="color: rgb(0, 128, 0);"&gt;// an artist property should exist&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  35:&lt;/span&gt;  &lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  36:&lt;/span&gt;                                   orderby playCountValues.Count() == 0? 0 : Int32.Parse(playCountValues.First().Value) descending&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  37:&lt;/span&gt;                                   select artistValues.First().Value).Distinct().ToList();&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  38:&lt;/span&gt;  &lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  39:&lt;/span&gt;                    Console.WriteLine(&lt;span style="color: rgb(0, 96, 128);"&gt;"Number of artists:"&lt;/span&gt; + artistNames.Count());&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  40:&lt;/span&gt;  &lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  41:&lt;/span&gt;                    &lt;span style="color: rgb(0, 128, 0);"&gt;// write out the artist names in decending order of popularity&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  42:&lt;/span&gt;                    &lt;span style="color: rgb(0, 0, 255);"&gt;foreach&lt;/span&gt; (var artistName &lt;span style="color: rgb(0, 0, 255);"&gt;in&lt;/span&gt; artistNames) {&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  43:&lt;/span&gt;                        Console.WriteLine(artistName);&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  44:&lt;/span&gt;                    }&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  45:&lt;/span&gt;                }&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  46:&lt;/span&gt;  &lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  47:&lt;/span&gt;                Console.WriteLine(&lt;span style="color: rgb(0, 96, 128);"&gt;"hit enter to exit"&lt;/span&gt;);&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  48:&lt;/span&gt;                Console.ReadLine();&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  49:&lt;/span&gt;        }&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  50:&lt;/span&gt;    }&lt;/pre&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"&gt;&lt;span style="color: rgb(96, 96, 96);"&gt;  51:&lt;/span&gt; }&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The &lt;em&gt;let&lt;/em&gt; keyword allows you to define a variable within a query. In my case, the playCountValues and artistValues are the each IEnumerable&amp;lt;XElements&amp;gt; of the play count and artist name respectively. &lt;em&gt;let &lt;/em&gt;is great for keeping variables that will be reused more than once elsewhere in the query.&lt;/p&gt;
&lt;p&gt;This query is a bit complex and unusually long because the iTunes XML doesn't store key-values like &lt;em&gt;&amp;lt;Name&amp;gt;DJ Shadow&amp;lt;/Name&amp;gt; &lt;/em&gt;(the typical format). Notice the need to get the value element with &lt;strong&gt;(element.NextNode as XElement)&lt;/strong&gt;. &lt;/p&gt;
&lt;p&gt;After running this on my friends library, the console spat out over 5000 lines of artist names. Success! Top of the list is "Zero 7". Second on the list is "DJ Shadow" - who I've never heard before. I'll definitely check these artists out.&lt;/p&gt;
&lt;p&gt;The next thing I'll do is find out what albums of "Zero 7" he's got and perhaps cross reference the list with the an Amazon page to find an album he doesn't own. This years birthday present decision will be completely automated :)&lt;/p&gt;
&lt;p&gt;Till next time on LINQ &amp;amp; Lambda, if there's any particular LINQ provider you want me to cover, please leave a message in the comments.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fvijay.screamingpens.com%2farchive%2f2008%2f05%2f05%2flinq-amp-lambda-part-1-itunes-xml-querying.aspx"&gt;&lt;img border="0" alt="kick it on DotNetKicks.com" src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fvijay.screamingpens.com%2farchive%2f2008%2f05%2f05%2flinq-amp-lambda-part-1-itunes-xml-querying.aspx" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://vijay.screamingpens.com/aggbug/9.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Vijay Santhanam</dc:creator>
            <guid>http://vijay.screamingpens.com/archive/2008/05/05/linq-amp-lambda-part-1-itunes-xml-querying.aspx</guid>
            <pubDate>Sun, 04 May 2008 15:37:13 GMT</pubDate>
            <wfw:comment>http://vijay.screamingpens.com/comments/9.aspx</wfw:comment>
            <comments>http://vijay.screamingpens.com/archive/2008/05/05/linq-amp-lambda-part-1-itunes-xml-querying.aspx#feedback</comments>
            <slash:comments>1</slash:comments>
            <wfw:commentRss>http://vijay.screamingpens.com/comments/commentRss/9.aspx</wfw:commentRss>
        </item>
        <item>
            <title>LINQ &amp;amp; Lambda</title>
            <link>http://vijay.screamingpens.com/archive/2008/05/04/linq-amp-lambda.aspx</link>
            <description>&lt;p&gt;I think I have a problem. I'm addicted to LINQ and Lambdas...&lt;/p&gt;  &lt;p&gt;Every opportunity I get to play with a new LINQ provider I take it. &lt;a href="http://www.hanselman.com/blog/LINQToEverythingLINQToXSDAddsMoreLINQiness.aspx"&gt;LINQ to XSD&lt;/a&gt;, &lt;a href="http://www.codeplex.com/linqtolucene"&gt;LINQ to Lucene&lt;/a&gt;, &lt;a href="www.codeplex.com/LINQFlickr"&gt;LINQ to Flickr&lt;/a&gt;, LINQ to SQL, &lt;a href="http://www.codeplex.com/linqextender"&gt;LINQ to *&lt;/a&gt; - you name it - I've &lt;strike&gt;injected&lt;/strike&gt; used it. &lt;/p&gt;  &lt;p&gt;And it seems I'm not the only one, with others confessing their &lt;a href="http://blog.wekeroad.com/blog/my-personal-lambda-crusade/"&gt;uncontrollable&lt;/a&gt; &lt;a href="http://msmvps.com/blogs/jon.skeet/archive/2007/11/02/i-love-linq-simplifying-a-tedious-task.aspx"&gt;attraction&lt;/a&gt; &lt;a href="http://blogs.msdn.com/helloworld/archive/2008/03/16/why-you-will-fall-in-love-with-linq.aspx"&gt;toward&lt;/a&gt; &lt;a href="http://weblogs.asp.net/stefansedich/archive/2007/12/24/i-think-i-love-linq.aspx"&gt;them&lt;/a&gt; too.&lt;/p&gt;  &lt;p&gt;Last week I spent a few days on an old C# 2 project. Within minutes, I was clutching for the sweet, &lt;strong&gt;sweet&lt;/strong&gt; 3.0 compiler. I couldn't stop sweating when writing event handler receivers like &lt;em&gt;&lt;strong&gt;delegate(object sender, EventArgs e) {}&lt;/strong&gt;&lt;/em&gt;. &lt;/p&gt;  &lt;p&gt;Calm down Vijay... they're just withdrawal symptoms... &lt;/p&gt;  &lt;p&gt;Oh the inner angst and turmoil! What do I do?! How do I expel the &lt;a href="http://www.sojo.net/index.cfm?action=magazine.article&amp;amp;issue=soj9605&amp;amp;article=960521"&gt;Demons&lt;/a&gt; from within?!&lt;/p&gt;  &lt;p&gt;I call these demons LINQ &amp;amp; Lambda, and they've irrecoverably changed the way I think - reprogrammed my brain.&lt;/p&gt;  &lt;p&gt;Last night, I dreamt of an anthropomorphism of these Demons. &lt;/p&gt;  &lt;p&gt;&lt;a href="http://vijay.screamingpens.com/images/vijay_screamingpens_com/WindowsLiveWriter/LINQLambda_EBE5/LINQ%20and%20Lambda_2.jpg"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; margin: 0px 0px 0px 75px; border-right-width: 0px" height="484" alt="LINQ and Lambda" src="http://vijay.screamingpens.com/images/vijay_screamingpens_com/WindowsLiveWriter/LINQLambda_EBE5/LINQ%20and%20Lambda_thumb.jpg" width="363" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Coincidentally, they &lt;a href="http://nathanielstern.com/blog/wp-content/prussianbluecopy.jpg"&gt;resemble&lt;/a&gt; the evil, innocent looking, white-nationalist pop duo &lt;a href="http://en.wikipedia.org/wiki/Prussian_Blue_(American_duo)"&gt;Prussian Blue&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Perhaps the best way to deal with them is to get the word out. Warn others of my folly and misadventure - in blog-series format.&lt;/p&gt;  &lt;p&gt;Stay tuned for Part 1 of LINQ &amp;amp; Lambda...&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fvijay.screamingpens.com%2farchive%2f2008%2f05%2f04%2flinq-amp-lambda.aspx"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fvijay.screamingpens.com%2farchive%2f2008%2f05%2f04%2flinq-amp-lambda.aspx" border="0" alt="kick it on DotNetKicks.com" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://vijay.screamingpens.com/aggbug/8.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Vijay Santhanam</dc:creator>
            <guid>http://vijay.screamingpens.com/archive/2008/05/04/linq-amp-lambda.aspx</guid>
            <pubDate>Sun, 04 May 2008 08:32:46 GMT</pubDate>
            <wfw:comment>http://vijay.screamingpens.com/comments/8.aspx</wfw:comment>
            <comments>http://vijay.screamingpens.com/archive/2008/05/04/linq-amp-lambda.aspx#feedback</comments>
            <slash:comments>5</slash:comments>
            <wfw:commentRss>http://vijay.screamingpens.com/comments/commentRss/8.aspx</wfw:commentRss>
        </item>
        <item>
            <title>A command line interface base class</title>
            <link>http://vijay.screamingpens.com/archive/2008/01/03/a-command-line-interface-base-class.aspx</link>
            <description>&lt;p&gt;I needed a simpler way build basic command line interfaces so I cobbled together a useful C# base class.&lt;/p&gt;
&lt;p&gt;I made the class as simple as possible to create entry point (start up) classes.&lt;/p&gt;
&lt;div&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;class&lt;/span&gt; Program :BaseConsole {&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0, 0, 255);"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;override&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;string&lt;/span&gt; Name {&lt;br /&gt;        get { &lt;span style="color: rgb(0, 0, 255);"&gt;return&lt;/span&gt; &lt;span style="color: rgb(0, 96, 128);"&gt;"Console Application"&lt;/span&gt;; }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0, 0, 255);"&gt;protected&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;override&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;void&lt;/span&gt; LoadCommands() {&lt;br /&gt;        &lt;span style="color: rgb(0, 0, 255);"&gt;this&lt;/span&gt;.Commands.Add(&lt;span style="color: rgb(0, 96, 128);"&gt;"print"&lt;/span&gt;, () =&amp;gt; Console.WriteLine(&lt;span style="color: rgb(0, 96, 128);"&gt;"print out"&lt;/span&gt;));&lt;br /&gt;        &lt;span style="color: rgb(0, 0, 255);"&gt;this&lt;/span&gt;.Commands.Add(&lt;span style="color: rgb(0, 96, 128);"&gt;"another"&lt;/span&gt;, () =&amp;gt; Console.WriteLine(&lt;span style="color: rgb(0, 96, 128);"&gt;"another print out"&lt;/span&gt;));&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0, 0, 255);"&gt;static&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;void&lt;/span&gt; Main(&lt;span style="color: rgb(0, 0, 255);"&gt;string&lt;/span&gt;[] args) {&lt;br /&gt;        &lt;span style="color: rgb(0, 0, 255);"&gt;new&lt;/span&gt; Program().Run();&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Just run a console application that starts the Main() of the Program class. Typing in any commands that have been added to &lt;strong&gt;&lt;em&gt;Commands&lt;/em&gt;&lt;/strong&gt; will invoke the associated action.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;table border="1" width="464"&gt;
    &lt;tbody&gt;
        &lt;tr&gt;
            &lt;td width="462"&gt;
            &lt;pre&gt;Console Application&lt;br /&gt;=====================================&lt;br /&gt;Type 'help' to get available commands&lt;br /&gt;Type 'exit','done' or 'quit' to exit&lt;br /&gt;&lt;br /&gt;&amp;gt;&amp;gt;print&lt;br /&gt;print out&lt;br /&gt;&lt;br /&gt;&amp;gt;&amp;gt;another&lt;br /&gt;another print out&lt;br /&gt;&lt;br /&gt;&amp;gt;&amp;gt;&lt;/pre&gt;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/tbody&gt;
&lt;/table&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;If you type "help" it will print a list of available commands. You can exit the program by typing "exit","quit" or "done".&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;The commands themselves are stored in a Dictionary&amp;lt;string,Action&amp;gt; - the new lambdas in C# 3 make writing inline functions so simple.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;p&gt;   &lt;/p&gt;
&lt;div style="margin: 0px; padding: 0px; display: inline; float: none;" id="scid:fb3a1972-4489-4e52-abe7-25a00bb07fdf:8762117c-2deb-4389-bfe8-73b35752052a" class="wlWriterSmartContent"&gt;
&lt;p&gt;Download it &lt;a href="http://vijay.screamingpens.com/images/vijay_screamingpens_com/WindowsLiveWriter/Acommandlineinterfacebaseclass_6123/BaseConsole.rar"&gt;here.&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;
&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fvijay.screamingpens.com%2farchive%2f2008%2f01%2f03%2fa-command-line-interface-base-class.aspx"&gt;&lt;img alt="kick it on DotNetKicks.com" src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fvijay.screamingpens.com%2farchive%2f2008%2f01%2f03%2fa-command-line-interface-base-class.aspx" border="0" /&gt;&lt;/a&gt;
&lt;/p&gt;&lt;img src="http://vijay.screamingpens.com/aggbug/6.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Vijay Santhanam</dc:creator>
            <guid>http://vijay.screamingpens.com/archive/2008/01/03/a-command-line-interface-base-class.aspx</guid>
            <pubDate>Wed, 02 Jan 2008 19:51:38 GMT</pubDate>
            <wfw:comment>http://vijay.screamingpens.com/comments/6.aspx</wfw:comment>
            <comments>http://vijay.screamingpens.com/archive/2008/01/03/a-command-line-interface-base-class.aspx#feedback</comments>
            <slash:comments>4</slash:comments>
            <wfw:commentRss>http://vijay.screamingpens.com/comments/commentRss/6.aspx</wfw:commentRss>
        </item>
        <item>
            <title>A more useful UrlBuilder class</title>
            <link>http://vijay.screamingpens.com/archive/2008/01/02/a-more-useful-urlbuilder-class.aspx</link>
            <description>&lt;p&gt;When I started my first ASP.NET project in 05, my URL building code included way too many string concatenations, String.Format calls and plain literals. &lt;/p&gt;
&lt;p&gt;Being pre-MS-MVC days of typed URL construction via routing engines, I needed some code to make URL construction (particularly the query string) easier. &lt;/p&gt;
&lt;p&gt;Then I found this &lt;a href="http://www.codeproject.com/KB/aspnet/UrlBuilder.aspx"&gt;UrlBuilder class&lt;/a&gt;. This is a great little class because it neatly derives from the framework UriBuilder class. &lt;/p&gt;
&lt;p&gt;Since I started using it, I found it was inadequate when dealing with case sensitive HTTP servers. The specialized StringDictionary it uses lower-cases all keys and values.&lt;/p&gt;
&lt;p&gt;To suit my needs, I modified the class in a few ways:&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;Upgraded to C# 3 - I think I'm addicted to lambda's so I involuntarily compiled it in .NET framework 3.5&lt;/li&gt;
    &lt;li&gt;The un-rendered query string is now stored as Dictionary&amp;lt;string,string&amp;gt; instead of StringDictionary which avoids casing problems &lt;/li&gt;
    &lt;li&gt;Provided overloads for ToString() casing - upper,lower or default (leaves casing alone) &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here's a simple example for building a Clickatell SMS sending URL.&lt;/p&gt;
&lt;pre class="csharpcode"&gt;UrlBuilder builder = &lt;span class="kwrd"&gt;new&lt;/span&gt; UrlBuilder(&lt;span class="str"&gt;"http://api.clickatell.com/http/sendmsg"&lt;/span&gt;);&lt;br /&gt;builder.QueryString[&lt;span class="str"&gt;"api_id"&lt;/span&gt;] = &lt;span class="str"&gt;"23223"&lt;/span&gt;;&lt;br /&gt;builder.QueryString[&lt;span class="str"&gt;"user"&lt;/span&gt;] = &lt;span class="str"&gt;"cutnpaste"&lt;/span&gt;;&lt;br /&gt;builder.QueryString[&lt;span class="str"&gt;"password"&lt;/span&gt;] = &lt;span class="str"&gt;"ninja"&lt;/span&gt;;&lt;br /&gt;builder.QueryString[&lt;span class="str"&gt;"to"&lt;/span&gt;] = &lt;span class="str"&gt;"61043678945"&lt;/span&gt;;&lt;br /&gt;builder.QueryString[&lt;span class="str"&gt;"text"&lt;/span&gt;] = &lt;span class="str"&gt;"the message to send"&lt;/span&gt;;&lt;br /&gt;Console.WriteLine(builder.ToString(StringCaseDirection.Lower));&lt;/pre&gt;
&lt;div style="margin: 0px; padding: 0px; display: inline;" id="scid:fb3a1972-4489-4e52-abe7-25a00bb07fdf:e18eb27c-f07d-497a-b16b-1fc2a5612119" class="wlWriterSmartContent"&gt;
&lt;p&gt;Download &lt;a target="_blank" href="http://vijay.screamingpens.com/images/vijay_screamingpens_com/WindowsLiveWriter/AnewusefulUrlBuilderclass_3A1C/UrlBuilder.zip"&gt;source code&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fvijay.screamingpens.com%2farchive%2f2008%2f01%2f02%2fa-more-useful-urlbuilder-class.aspx"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fvijay.screamingpens.com%2farchive%2f2008%2f01%2f02%2fa-more-useful-urlbuilder-class.aspx" border="0" alt="kick it on DotNetKicks.com" /&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;/div&gt;&lt;img src="http://vijay.screamingpens.com/aggbug/5.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Vijay Santhanam</dc:creator>
            <guid>http://vijay.screamingpens.com/archive/2008/01/02/a-more-useful-urlbuilder-class.aspx</guid>
            <pubDate>Tue, 01 Jan 2008 17:33:28 GMT</pubDate>
            <wfw:comment>http://vijay.screamingpens.com/comments/5.aspx</wfw:comment>
            <comments>http://vijay.screamingpens.com/archive/2008/01/02/a-more-useful-urlbuilder-class.aspx#feedback</comments>
            <slash:comments>2</slash:comments>
            <wfw:commentRss>http://vijay.screamingpens.com/comments/commentRss/5.aspx</wfw:commentRss>
        </item>
    </channel>
</rss>