<?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:pingback="http://madskills.com/public/xml/rss/module/pingback/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
  <channel>
    <title>VibrantCode - Cool Software</title>
    <link>http://blog.andrewnurse.net/</link>
    <description>Oooh...pretty code</description>
    <language>en-us</language>
    <copyright>Andrew Nurse</copyright>
    <lastBuildDate>Fri, 10 Apr 2009 21:42:49 GMT</lastBuildDate>
    <generator>newtelligence dasBlog 2.0.7226.0</generator>
    <managingEditor>andrew@andrewnurse.net</managingEditor>
    <webMaster>andrew@andrewnurse.net</webMaster>
    <item>
      <trackback:ping>http://blog.andrewnurse.net/Trackback.aspx?guid=9425e19f-3119-4880-9f2f-cd5b5c445825</trackback:ping>
      <pingback:server>http://blog.andrewnurse.net/pingback.aspx</pingback:server>
      <pingback:target>http://blog.andrewnurse.net/PermaLink,guid,9425e19f-3119-4880-9f2f-cd5b5c445825.aspx</pingback:target>
      <dc:creator>Andrew Nurse</dc:creator>
      <wfw:comment>http://blog.andrewnurse.net/CommentView,guid,9425e19f-3119-4880-9f2f-cd5b5c445825.aspx</wfw:comment>
      <wfw:commentRss>http://blog.andrewnurse.net/SyndicationService.asmx/GetEntryCommentsRss?guid=9425e19f-3119-4880-9f2f-cd5b5c445825</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Hello avid readers!  It’s been over a week since I blogged, I know, but I’ve
been cramming for exams.  The CMPT 376 assignment I mentioned a while ago has
finished, so I’m no longer required to blog for grades.  Having said that, after
exams, I plan to keep blogging, so keep watching the feed :).
</p>
        <p>
Just to tease you a bit: I’ve got a cool little ASP.Net MVC side-project well underway
that I’m just dying to show off on the blog, so stick around :P
</p>
        <p>
Also, to the Reports Module users out there, 5.1 is very close to being finished. 
There may be a surprise new feature in there too.  Details to follow later :D.
</p>
        <img width="0" height="0" src="http://blog.andrewnurse.net/aggbug.ashx?id=9425e19f-3119-4880-9f2f-cd5b5c445825" />
      </body>
      <title>I&amp;rsquo;m still here&amp;hellip; just cramming&amp;hellip; and working</title>
      <guid isPermaLink="false">http://blog.andrewnurse.net/PermaLink,guid,9425e19f-3119-4880-9f2f-cd5b5c445825.aspx</guid>
      <link>http://blog.andrewnurse.net/2009/04/10/IrsquomStillHerehellipJustCramminghellipAndWorking.aspx</link>
      <pubDate>Fri, 10 Apr 2009 21:42:49 GMT</pubDate>
      <description>&lt;p&gt;
Hello avid readers!&amp;#160; It’s been over a week since I blogged, I know, but I’ve
been cramming for exams.&amp;#160; The CMPT 376 assignment I mentioned a while ago has
finished, so I’m no longer required to blog for grades.&amp;#160; Having said that, after
exams, I plan to keep blogging, so keep watching the feed :).
&lt;/p&gt;
&lt;p&gt;
Just to tease you a bit: I’ve got a cool little ASP.Net MVC side-project well underway
that I’m just dying to show off on the blog, so stick around :P
&lt;/p&gt;
&lt;p&gt;
Also, to the Reports Module users out there, 5.1 is very close to being finished.&amp;#160;
There may be a surprise new feature in there too.&amp;#160; Details to follow later :D.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://blog.andrewnurse.net/aggbug.ashx?id=9425e19f-3119-4880-9f2f-cd5b5c445825" /&gt;</description>
      <comments>http://blog.andrewnurse.net/CommentView,guid,9425e19f-3119-4880-9f2f-cd5b5c445825.aspx</comments>
      <category>Cool Software</category>
      <category>DNN</category>
      <category>MVC</category>
      <category>Reports Module</category>
    </item>
    <item>
      <trackback:ping>http://blog.andrewnurse.net/Trackback.aspx?guid=027622e1-c0f4-4cb2-b75c-f990ef7d3ac4</trackback:ping>
      <pingback:server>http://blog.andrewnurse.net/pingback.aspx</pingback:server>
      <pingback:target>http://blog.andrewnurse.net/PermaLink,guid,027622e1-c0f4-4cb2-b75c-f990ef7d3ac4.aspx</pingback:target>
      <dc:creator>Andrew Nurse</dc:creator>
      <wfw:comment>http://blog.andrewnurse.net/CommentView,guid,027622e1-c0f4-4cb2-b75c-f990ef7d3ac4.aspx</wfw:comment>
      <wfw:commentRss>http://blog.andrewnurse.net/SyndicationService.asmx/GetEntryCommentsRss?guid=027622e1-c0f4-4cb2-b75c-f990ef7d3ac4</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Microsoft is really taking major strides in terms of improving the programming experience
for developers on all current and <strong>future</strong> computing platforms. 
That’s why, earlier today, Microsoft released a beta of the new “System.QuantumEntanglement”
library.  This library, being considered for integration with .Net 4.1 (which,
my sources say, is codenamed “Looflirpa”), provides features for developers working
on quantum computers.  I won’t go in to too much detail, but this essentially
means working in an environment where objects can be in many different states (possibly
an infinite number) and where observation may change the state of an object. 
Microsoft has proposed a few options, but I have some additional ideas.
</p>
        <h2>Microsoft’s Proposal
</h2>
        <p>
          <a href="http://weblogs.asp.net/leftslipper/" target="_blank">Eilon Lipton</a>, of
the ASP.Net MVC team, <a href="http://weblogs.asp.net/leftslipper/archive/2009/04/01/the-string-or-the-cat-a-new-net-framework-library.aspx" target="_blank">is
proposing a number of new additions to the .Net BCL in 4.1</a>.  The first, is
a class called “StringOr&lt;T&gt;” which has the following API:
</p>
        <pre class="csharp" name="code">namespace System.QuantumEntanglement {
    public class StringOr&lt;TOther&gt; {
        public StringOr(string stringValue, TOther otherValue);

        public string StringValue { get; }
        public TOther OtherValue { get; }
    }
}</pre>
        <p>
This class is used to encapsulate a value which may be a string, but may be another
value.  This is a common user-input scenario, since almost all user input arrives
as strings, but will usually be converted to another data type.  He also proposes
a more general class called “SchrodingOr&lt;TDead, TAlive&gt;”
</p>
        <pre class="csharp" name="code">namespace System.QuantumEntanglement {
    public class SchrodingOr&lt;TDead, TAlive&gt; {
        public SchrodingOr(TDead dead, TAlive alive);

        public TAlive Alive { get; }
        public TDead Dead { get; }
    }
}</pre>
        <p>
This generalizes StringOr&lt;T&gt; to support any two types.  
</p>
        <p>
Eilon’s not the only one talking about this, <a href="http://www.hanselman.com/blog/NET41PreviewNewBaseClassLibraryBCLExtensionMethodsRFC.aspx" target="_blank">Scott
Hanselman</a> (well known Microsoft blogger), and <a href="http://blog.wekeroad.com/blog/cool-extension-methods-for-new-stringor/" target="_blank">Rob
Conery</a> (Author of the .Net Object-Relational Mapper: SubSonic) have also posted
on this topic.  So I figured I’d add my comments to the blogosphere.
</p>
        <p>
StringOr and SchrodingOr are great starts, but what if we need to represent objects
which may be in 2 states? What about 3 states? Infinite states?  That’s where
my proposals come in.  I propose the following additions to Eilon’s library:
</p>
        <h2>Generalizing SchrodingOr
</h2>
        <p>
The first is SchrodingOr&lt;T1, T2, T3, T4, T5, … , T<em>n</em>&gt; (for infinite <em>n</em>). 
This allows the developer to represent objects in as many states as they want.  
</p>
        <h2>C# 5.0 Compiler Support
</h2>
        <p>
I’m also proposing the following language syntax to help developers work with these
types.  Similar to the way the C# compiler converts “int?” to “Nullable&lt;int&gt;”
(which would now be replaced with “SchrodingOr&lt;int, Void&gt;” as it more accurately
represents the concept of a type which may or may not have a value), the new syntax
takes the following:
</p>
        <pre class="csharp" name="code">int?string?bool?DateTime? foo = GetUserInput(...);</pre>
        <p>
And produces output code which looks like this:
</p>
        <pre class="csharp" name="code">SchrodingOr&lt;int, DateTime, bool, string&gt; foo = GetUserInput(...);</pre>
        <p>
Then, we can defer observation until a later time, using the AsA&lt;T&gt;/AsAn&lt;T&gt;
method (since Eilon's Alive and Dead properties no longer work in an infinite state
environment). If we just want to observe the type and then make a decision, we can
use IsA&lt;T&gt;/IsAn&lt;T&gt; methods (of course, both are required, just in case
the type starts with a vowel), which returns a boolean indicating if the object is
of the type <em>T</em>. For example:
</p>
        <pre class="csharp" name="code">if(foo.IsA&lt;string&gt;()) { return foo.AsA&lt;string;&gt;; }</pre>
        <h2>
        </h2>
        <h2>Probabilistic Observation
</h2>
        <p>
Sometimes, we may want to observe an object only if there is a high probability of
it being in the right state, to avoid additional quantum variations. To do this, we
can use the CouldBeA&lt;T&gt;/CouldBeA&lt;T&gt; methods. These can, optionally, accept
a probability threshold beyond which a object is considered in the right state.
</p>
        <h2>Quantum Snapshots
</h2>
        <p>
Unfortunately, in between a call to IsA/An/CouldBeA/An and AsA/An, the state of the
object may change.  So, we may wish to observe an object and record the state
of the object at the time of observation.  Since in observing the object we may
change its state, our observations must be recorded in “Snapshots”.  The snapshot
is an instance of QuantumSnapshotOf&lt;TSchrodingOr&gt; (where <em>TSchrodingOr</em> must
be one of the SchrodingOr&lt;T1, ..., T<em>n</em>&gt; types), and has a property "Taken",
which is a DateTimeOffset (after all, we need precise timing here) containing the
exact time that the snapshot was taken. 
</p>
        <p>
Here’s an example combining Probabilistic Observation and Snapshots:
</p>
        <pre class="csharp" name="code">if(foo.CouldBeA&lt;string&gt;()) {
	QuantumSnapshotOf&lt;SchrodingOr&lt;int, string&gt;&gt; snapshot = foo.Observe();
	if(snapshot.Taken.Day == 1 &amp;&amp; snapshot.Taken.Month == 4) {
		throw new UnreliableObservationException(snapshot, "The data is unreliable");
	}
	return snapshot.AsA&lt;string&gt;();
}</pre>
        <h2>Summary
</h2>
        <p>
I think this is really interesting, forward-thinking, stuff from Microsoft. Eilon
has done some fantastic work getting the ball rolling, and its up to us to give our
feedback! Microsoft has created a section on MSDN for discussion on these new features: <a href="http://en.wikipedia.org/wiki/April_Fool%27s_Day" target="_blank">http://msdn.microsoft.com/en-US/QuantumEntanglement/Default.aspx</a></p>
        <img width="0" height="0" src="http://blog.andrewnurse.net/aggbug.ashx?id=027622e1-c0f4-4cb2-b75c-f990ef7d3ac4" />
      </body>
      <title>Quantum Computing in .Net &amp;ldquo;Looflirpa&amp;rdquo;</title>
      <guid isPermaLink="false">http://blog.andrewnurse.net/PermaLink,guid,027622e1-c0f4-4cb2-b75c-f990ef7d3ac4.aspx</guid>
      <link>http://blog.andrewnurse.net/2009/04/01/QuantumComputingInNetLdquoLooflirpardquo.aspx</link>
      <pubDate>Wed, 01 Apr 2009 09:29:47 GMT</pubDate>
      <description>&lt;p&gt;
Microsoft is really taking major strides in terms of improving the programming experience
for developers on all current and &lt;strong&gt;future&lt;/strong&gt; computing platforms.&amp;#160;
That’s why, earlier today, Microsoft released a beta of the new “System.QuantumEntanglement”
library.&amp;#160; This library, being considered for integration with .Net 4.1 (which,
my sources say, is codenamed “Looflirpa”), provides features for developers working
on quantum computers.&amp;#160; I won’t go in to too much detail, but this essentially
means working in an environment where objects can be in many different states (possibly
an infinite number) and where observation may change the state of an object.&amp;#160;
Microsoft has proposed a few options, but I have some additional ideas.
&lt;/p&gt;
&lt;h2&gt;Microsoft’s Proposal
&lt;/h2&gt;
&lt;p&gt;
&lt;a href="http://weblogs.asp.net/leftslipper/" target="_blank"&gt;Eilon Lipton&lt;/a&gt;, of
the ASP.Net MVC team, &lt;a href="http://weblogs.asp.net/leftslipper/archive/2009/04/01/the-string-or-the-cat-a-new-net-framework-library.aspx" target="_blank"&gt;is
proposing a number of new additions to the .Net BCL in 4.1&lt;/a&gt;.&amp;#160; The first, is
a class called “StringOr&amp;lt;T&amp;gt;” which has the following API:
&lt;/p&gt;
&lt;pre class="csharp" name="code"&gt;namespace System.QuantumEntanglement {
    public class StringOr&amp;lt;TOther&amp;gt; {
        public StringOr(string stringValue, TOther otherValue);

        public string StringValue { get; }
        public TOther OtherValue { get; }
    }
}&lt;/pre&gt;
&lt;p&gt;
This class is used to encapsulate a value which may be a string, but may be another
value.&amp;#160; This is a common user-input scenario, since almost all user input arrives
as strings, but will usually be converted to another data type.&amp;#160; He also proposes
a more general class called “SchrodingOr&amp;lt;TDead, TAlive&amp;gt;”
&lt;/p&gt;
&lt;pre class="csharp" name="code"&gt;namespace System.QuantumEntanglement {
    public class SchrodingOr&amp;lt;TDead, TAlive&amp;gt; {
        public SchrodingOr(TDead dead, TAlive alive);

        public TAlive Alive { get; }
        public TDead Dead { get; }
    }
}&lt;/pre&gt;
&lt;p&gt;
This generalizes StringOr&amp;lt;T&amp;gt; to support any two types.&amp;#160; 
&lt;/p&gt;
&lt;p&gt;
Eilon’s not the only one talking about this, &lt;a href="http://www.hanselman.com/blog/NET41PreviewNewBaseClassLibraryBCLExtensionMethodsRFC.aspx" target="_blank"&gt;Scott
Hanselman&lt;/a&gt; (well known Microsoft blogger), and &lt;a href="http://blog.wekeroad.com/blog/cool-extension-methods-for-new-stringor/" target="_blank"&gt;Rob
Conery&lt;/a&gt; (Author of the .Net Object-Relational Mapper: SubSonic) have also posted
on this topic.&amp;#160; So I figured I’d add my comments to the blogosphere.
&lt;/p&gt;
&lt;p&gt;
StringOr and SchrodingOr are great starts, but what if we need to represent objects
which may be in 2 states? What about 3 states? Infinite states?&amp;#160; That’s where
my proposals come in.&amp;#160; I propose the following additions to Eilon’s library:
&lt;/p&gt;
&lt;h2&gt;Generalizing SchrodingOr
&lt;/h2&gt;
&lt;p&gt;
The first is SchrodingOr&amp;lt;T1, T2, T3, T4, T5, … , T&lt;em&gt;n&lt;/em&gt;&amp;gt; (for infinite &lt;em&gt;n&lt;/em&gt;).&amp;#160;
This allows the developer to represent objects in as many states as they want.&amp;#160; 
&lt;/p&gt;
&lt;h2&gt;C# 5.0 Compiler Support
&lt;/h2&gt;
&lt;p&gt;
I’m also proposing the following language syntax to help developers work with these
types.&amp;#160; Similar to the way the C# compiler converts “int?” to “Nullable&amp;lt;int&amp;gt;”
(which would now be replaced with “SchrodingOr&amp;lt;int, Void&amp;gt;” as it more accurately
represents the concept of a type which may or may not have a value), the new syntax
takes the following:
&lt;/p&gt;
&lt;pre class="csharp" name="code"&gt;int?string?bool?DateTime? foo = GetUserInput(...);&lt;/pre&gt;
&lt;p&gt;
And produces output code which looks like this:
&lt;/p&gt;
&lt;pre class="csharp" name="code"&gt;SchrodingOr&amp;lt;int, DateTime, bool, string&amp;gt; foo = GetUserInput(...);&lt;/pre&gt;
&lt;p&gt;
Then, we can defer observation until a later time, using the AsA&amp;lt;T&amp;gt;/AsAn&amp;lt;T&amp;gt;
method (since Eilon's Alive and Dead properties no longer work in an infinite state
environment). If we just want to observe the type and then make a decision, we can
use IsA&amp;lt;T&amp;gt;/IsAn&amp;lt;T&amp;gt; methods (of course, both are required, just in case
the type starts with a vowel), which returns a boolean indicating if the object is
of the type &lt;em&gt;T&lt;/em&gt;. For example:
&lt;/p&gt;
&lt;pre class="csharp" name="code"&gt;if(foo.IsA&amp;lt;string&amp;gt;()) { return foo.AsA&amp;lt;string;&amp;gt;; }&lt;/pre&gt;
&lt;h2&gt;
&lt;/h2&gt;
&lt;h2&gt;Probabilistic Observation
&lt;/h2&gt;
&lt;p&gt;
Sometimes, we may want to observe an object only if there is a high probability of
it being in the right state, to avoid additional quantum variations. To do this, we
can use the CouldBeA&amp;lt;T&amp;gt;/CouldBeA&amp;lt;T&amp;gt; methods. These can, optionally, accept
a probability threshold beyond which a object is considered in the right state.
&lt;/p&gt;
&lt;h2&gt;Quantum Snapshots
&lt;/h2&gt;
&lt;p&gt;
Unfortunately, in between a call to IsA/An/CouldBeA/An and AsA/An, the state of the
object may change.&amp;#160; So, we may wish to observe an object and record the state
of the object at the time of observation.&amp;#160; Since in observing the object we may
change its state, our observations must be recorded in “Snapshots”.&amp;#160; The snapshot
is an instance of QuantumSnapshotOf&amp;lt;TSchrodingOr&amp;gt; (where &lt;em&gt;TSchrodingOr&lt;/em&gt; must
be one of the SchrodingOr&amp;lt;T1, ..., T&lt;em&gt;n&lt;/em&gt;&amp;gt; types), and has a property &amp;quot;Taken&amp;quot;,
which is a DateTimeOffset (after all, we need precise timing here) containing the
exact time that the snapshot was taken. 
&lt;/p&gt;
&lt;p&gt;
Here’s an example combining Probabilistic Observation and Snapshots:
&lt;/p&gt;
&lt;pre class="csharp" name="code"&gt;if(foo.CouldBeA&amp;lt;string&amp;gt;()) {
	QuantumSnapshotOf&amp;lt;SchrodingOr&amp;lt;int, string&amp;gt;&amp;gt; snapshot = foo.Observe();
	if(snapshot.Taken.Day == 1 &amp;amp;&amp;amp; snapshot.Taken.Month == 4) {
		throw new UnreliableObservationException(snapshot, &amp;quot;The data is unreliable&amp;quot;);
	}
	return snapshot.AsA&amp;lt;string&amp;gt;();
}&lt;/pre&gt;
&lt;h2&gt;Summary
&lt;/h2&gt;
&lt;p&gt;
I think this is really interesting, forward-thinking, stuff from Microsoft. Eilon
has done some fantastic work getting the ball rolling, and its up to us to give our
feedback! Microsoft has created a section on MSDN for discussion on these new features: &lt;a href="http://en.wikipedia.org/wiki/April_Fool%27s_Day" target="_blank"&gt;http://msdn.microsoft.com/en-US/QuantumEntanglement/Default.aspx&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://blog.andrewnurse.net/aggbug.ashx?id=027622e1-c0f4-4cb2-b75c-f990ef7d3ac4" /&gt;</description>
      <comments>http://blog.andrewnurse.net/CommentView,guid,027622e1-c0f4-4cb2-b75c-f990ef7d3ac4.aspx</comments>
      <category>CMPT 376</category>
      <category>Cool Software</category>
    </item>
    <item>
      <trackback:ping>http://blog.andrewnurse.net/Trackback.aspx?guid=b3dcd5f0-45b9-4454-bd29-604311e3166a</trackback:ping>
      <pingback:server>http://blog.andrewnurse.net/pingback.aspx</pingback:server>
      <pingback:target>http://blog.andrewnurse.net/PermaLink,guid,b3dcd5f0-45b9-4454-bd29-604311e3166a.aspx</pingback:target>
      <dc:creator>Andrew Nurse</dc:creator>
      <wfw:comment>http://blog.andrewnurse.net/CommentView,guid,b3dcd5f0-45b9-4454-bd29-604311e3166a.aspx</wfw:comment>
      <wfw:commentRss>http://blog.andrewnurse.net/SyndicationService.asmx/GetEntryCommentsRss?guid=b3dcd5f0-45b9-4454-bd29-604311e3166a</wfw:commentRss>
      <slash:comments>2</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Back in January, I started <a href="http://blog.andrewnurse.net/2009/01/08/WritingABlogForFunAndProfithellipIMeanGrades.aspx" target="_blank">blogging
more frequently due to a course I was taking</a>.  As part of that, I started
using Windows Live Writer to write all my blog posts.  I use the <a href="http://www.dasblog.info/" target="_blank">DasBlog</a> engine
to power my blog, and it supports one of the many blogging APIs that Windows Live
Writer uses (I believe it’s MetaWeblog).  So, I hooked it up to my blog, and
everything just worked!
</p>
        <p>
My favorite feature is the ability to create and save drafts and then publish them
on demand.  I have inspiration at the strangest times, and often in large batches,
so I end up with a couple ideas of things to blog in a day, and no ideas the next
day.  So, I just create a bunch of drafts, get them ready to publish and then
publish them over a longer period of time (like say… a day :P).  For example,
I wrote this post 5 minutes after the previous post, but I thought it might overload
my readers to post it immediately :).  So, I save a draft and post it a bit later
(when I don’t have anything to blog about :D).
</p>
        <p>
If you have a blog, and it supports one of the blogging APIs, and you’re running on
Windows, you really should try Windows Live Writer!
</p>
        <img width="0" height="0" src="http://blog.andrewnurse.net/aggbug.ashx?id=b3dcd5f0-45b9-4454-bd29-604311e3166a" />
      </body>
      <title>Windows Live Writer &amp;ndash; After 2 Months</title>
      <guid isPermaLink="false">http://blog.andrewnurse.net/PermaLink,guid,b3dcd5f0-45b9-4454-bd29-604311e3166a.aspx</guid>
      <link>http://blog.andrewnurse.net/2009/03/27/WindowsLiveWriterNdashAfter2Months.aspx</link>
      <pubDate>Fri, 27 Mar 2009 07:39:23 GMT</pubDate>
      <description>&lt;p&gt;
Back in January, I started &lt;a href="http://blog.andrewnurse.net/2009/01/08/WritingABlogForFunAndProfithellipIMeanGrades.aspx" target="_blank"&gt;blogging
more frequently due to a course I was taking&lt;/a&gt;.&amp;#160; As part of that, I started
using Windows Live Writer to write all my blog posts.&amp;#160; I use the &lt;a href="http://www.dasblog.info/" target="_blank"&gt;DasBlog&lt;/a&gt; engine
to power my blog, and it supports one of the many blogging APIs that Windows Live
Writer uses (I believe it’s MetaWeblog).&amp;#160; So, I hooked it up to my blog, and
everything just worked!
&lt;/p&gt;
&lt;p&gt;
My favorite feature is the ability to create and save drafts and then publish them
on demand.&amp;#160; I have inspiration at the strangest times, and often in large batches,
so I end up with a couple ideas of things to blog in a day, and no ideas the next
day.&amp;#160; So, I just create a bunch of drafts, get them ready to publish and then
publish them over a longer period of time (like say… a day :P).&amp;#160; For example,
I wrote this post 5 minutes after the previous post, but I thought it might overload
my readers to post it immediately :).&amp;#160; So, I save a draft and post it a bit later
(when I don’t have anything to blog about :D).
&lt;/p&gt;
&lt;p&gt;
If you have a blog, and it supports one of the blogging APIs, and you’re running on
Windows, you really should try Windows Live Writer!
&lt;/p&gt;
&lt;img width="0" height="0" src="http://blog.andrewnurse.net/aggbug.ashx?id=b3dcd5f0-45b9-4454-bd29-604311e3166a" /&gt;</description>
      <comments>http://blog.andrewnurse.net/CommentView,guid,b3dcd5f0-45b9-4454-bd29-604311e3166a.aspx</comments>
      <category>CMPT 376</category>
      <category>Cool Software</category>
    </item>
    <item>
      <trackback:ping>http://blog.andrewnurse.net/Trackback.aspx?guid=a97379a1-ad74-4a0a-9a2f-e5784a03b891</trackback:ping>
      <pingback:server>http://blog.andrewnurse.net/pingback.aspx</pingback:server>
      <pingback:target>http://blog.andrewnurse.net/PermaLink,guid,a97379a1-ad74-4a0a-9a2f-e5784a03b891.aspx</pingback:target>
      <dc:creator>Andrew Nurse</dc:creator>
      <wfw:comment>http://blog.andrewnurse.net/CommentView,guid,a97379a1-ad74-4a0a-9a2f-e5784a03b891.aspx</wfw:comment>
      <wfw:commentRss>http://blog.andrewnurse.net/SyndicationService.asmx/GetEntryCommentsRss?guid=a97379a1-ad74-4a0a-9a2f-e5784a03b891</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
So, as an MSDN subscriber (no, I’m not made of money, Microsoft Interns get a free
year-long subscription to MSDN for personal use :P), I had access to the Windows 7
public beta a day early.  I decided to go crazy, since I’ve been hearing its
really stable, and put the latest OS on both my laptop <strong>and </strong>my desktop. 
(Well, I actually put Windows 7 Server, aka Windows Server 2008 R2 on my desktop). 
So, I figured I’d post my first impressions.
</p>
        <h2>Installation
</h2>
        <p>
There’s not much to say here, Installation is exactly like Windows Vista, only a little
faster.  The only new feature is that Windows 7 Setup prompts you to create a
HomeGroup, if you want.  HomeGroups are the new networking construct introduced
in Windows 7 designed to make it easier to share files and devices between networked
computers.  I haven’t had a change to check that out yet, so I’ll come back to
it later.
</p>
        <h2>Initial Impression
</h2>
        <p>
Besides a stylish new boot screen, in which four coloured dots dance around before
combining to form the Windows logo, the boot process is also identical to Windows
Vista.  I did find that it booted up much faster than Vista (though I can’t make
an accurate comparison, since my laptop was getting a bit overloaded).  The new
taskbar is very cool, and while it is a bit of a knock-off of the OSX Dock, I think
Microsoft has (in typical Microsoft fashion) gone above and beyond the OSX experience. 
For example, by hovering the mouse over an icon, a list of all the windows belonging
to that application appears.  Even better, applications which directly support
Windows 7 can add their own “windows” to this list.  For example, even though
I only have one IE8 window open, each tab in that window appears as a separate item
in the windows list.
</p>
        <p>
          <a href="http://blog.andrewnurse.net/content/binary/WindowsLiveWriter/Windows7FirstImpressions_CD0A/image_2.png">
            <img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Taskbar Windows List" border="0" alt="Taskbar Windows List" src="http://blog.andrewnurse.net/content/binary/WindowsLiveWriter/Windows7FirstImpressions_CD0A/image_thumb.png" width="716" height="264" />
          </a>
        </p>
        <p>
By hovering over each thumbnail, that window is brought to focus on the screen, and
the rest of the windows become “glass”.
</p>
        <p>
          <a href="http://blog.andrewnurse.net/content/binary/WindowsLiveWriter/Windows7FirstImpressions_CD0A/image_4.png">
            <img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Peeking at a Window" border="0" alt="Peeking at a Window" src="http://blog.andrewnurse.net/content/binary/WindowsLiveWriter/Windows7FirstImpressions_CD0A/image_thumb_1.png" width="644" height="337" />
          </a>
        </p>
        <p>
(And yes, I did blank out my Windows Messenger buddies list :P).
</p>
        <p>
Jump lists are another cool feature, but I haven’t had a chance to explore it much. 
Essentially, when you right click, or click and drag up on one of these taskbar icons,
a jump list appears.
</p>
        <p>
          <a href="http://blog.andrewnurse.net/content/binary/WindowsLiveWriter/Windows7FirstImpressions_CD0A/image_6.png">
            <img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="IE8 Jumplist" border="0" alt="IE8 Jumplist" src="http://blog.andrewnurse.net/content/binary/WindowsLiveWriter/Windows7FirstImpressions_CD0A/image_thumb_2.png" width="287" height="599" />
          </a>
        </p>
        <p>
In this case (Internet Explorer 8), my history is displayed.  Applications designed
for Windows 7, get a lot of control over this list, but applications which are not
designed to support it (PowerShell 2.0 for example) just get a simple default list
</p>
        <p>
          <a href="http://blog.andrewnurse.net/content/binary/WindowsLiveWriter/Windows7FirstImpressions_CD0A/image_8.png">
            <img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="PowerShell 2.0 Jumplist" border="0" alt="PowerShell 2.0 Jumplist" src="http://blog.andrewnurse.net/content/binary/WindowsLiveWriter/Windows7FirstImpressions_CD0A/image_thumb_3.png" width="298" height="131" />
          </a>
        </p>
        <h2>
        </h2>
        <p>
        </p>
        <p>
I haven’t had much of a chance to explore the rest of the new stuff, so I’ll post
more later, but my initial impression is that Windows 7 is just plain awesome :).
</p>
        <img width="0" height="0" src="http://blog.andrewnurse.net/aggbug.ashx?id=a97379a1-ad74-4a0a-9a2f-e5784a03b891" />
      </body>
      <title>Windows 7 First Impressions</title>
      <guid isPermaLink="false">http://blog.andrewnurse.net/PermaLink,guid,a97379a1-ad74-4a0a-9a2f-e5784a03b891.aspx</guid>
      <link>http://blog.andrewnurse.net/2009/01/13/Windows7FirstImpressions.aspx</link>
      <pubDate>Tue, 13 Jan 2009 22:35:29 GMT</pubDate>
      <description>&lt;p&gt;
So, as an MSDN subscriber (no, I’m not made of money, Microsoft Interns get a free
year-long subscription to MSDN for personal use :P), I had access to the Windows 7
public beta a day early.&amp;#160; I decided to go crazy, since I’ve been hearing its
really stable, and put the latest OS on both my laptop &lt;strong&gt;and &lt;/strong&gt;my desktop.&amp;#160;
(Well, I actually put Windows 7 Server, aka Windows Server 2008 R2 on my desktop).&amp;#160;
So, I figured I’d post my first impressions.
&lt;/p&gt;
&lt;h2&gt;Installation
&lt;/h2&gt;
&lt;p&gt;
There’s not much to say here, Installation is exactly like Windows Vista, only a little
faster.&amp;#160; The only new feature is that Windows 7 Setup prompts you to create a
HomeGroup, if you want.&amp;#160; HomeGroups are the new networking construct introduced
in Windows 7 designed to make it easier to share files and devices between networked
computers.&amp;#160; I haven’t had a change to check that out yet, so I’ll come back to
it later.
&lt;/p&gt;
&lt;h2&gt;Initial Impression
&lt;/h2&gt;
&lt;p&gt;
Besides a stylish new boot screen, in which four coloured dots dance around before
combining to form the Windows logo, the boot process is also identical to Windows
Vista.&amp;#160; I did find that it booted up much faster than Vista (though I can’t make
an accurate comparison, since my laptop was getting a bit overloaded).&amp;#160; The new
taskbar is very cool, and while it is a bit of a knock-off of the OSX Dock, I think
Microsoft has (in typical Microsoft fashion) gone above and beyond the OSX experience.&amp;#160;
For example, by hovering the mouse over an icon, a list of all the windows belonging
to that application appears.&amp;#160; Even better, applications which directly support
Windows 7 can add their own “windows” to this list.&amp;#160; For example, even though
I only have one IE8 window open, each tab in that window appears as a separate item
in the windows list.
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://blog.andrewnurse.net/content/binary/WindowsLiveWriter/Windows7FirstImpressions_CD0A/image_2.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Taskbar Windows List" border="0" alt="Taskbar Windows List" src="http://blog.andrewnurse.net/content/binary/WindowsLiveWriter/Windows7FirstImpressions_CD0A/image_thumb.png" width="716" height="264" /&gt;&lt;/a&gt; 
&lt;/p&gt;
&lt;p&gt;
By hovering over each thumbnail, that window is brought to focus on the screen, and
the rest of the windows become “glass”.
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://blog.andrewnurse.net/content/binary/WindowsLiveWriter/Windows7FirstImpressions_CD0A/image_4.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Peeking at a Window" border="0" alt="Peeking at a Window" src="http://blog.andrewnurse.net/content/binary/WindowsLiveWriter/Windows7FirstImpressions_CD0A/image_thumb_1.png" width="644" height="337" /&gt;&lt;/a&gt; 
&lt;/p&gt;
&lt;p&gt;
(And yes, I did blank out my Windows Messenger buddies list :P).
&lt;/p&gt;
&lt;p&gt;
Jump lists are another cool feature, but I haven’t had a chance to explore it much.&amp;#160;
Essentially, when you right click, or click and drag up on one of these taskbar icons,
a jump list appears.
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://blog.andrewnurse.net/content/binary/WindowsLiveWriter/Windows7FirstImpressions_CD0A/image_6.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="IE8 Jumplist" border="0" alt="IE8 Jumplist" src="http://blog.andrewnurse.net/content/binary/WindowsLiveWriter/Windows7FirstImpressions_CD0A/image_thumb_2.png" width="287" height="599" /&gt;&lt;/a&gt; 
&lt;/p&gt;
&lt;p&gt;
In this case (Internet Explorer 8), my history is displayed.&amp;#160; Applications designed
for Windows 7, get a lot of control over this list, but applications which are not
designed to support it (PowerShell 2.0 for example) just get a simple default list
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://blog.andrewnurse.net/content/binary/WindowsLiveWriter/Windows7FirstImpressions_CD0A/image_8.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="PowerShell 2.0 Jumplist" border="0" alt="PowerShell 2.0 Jumplist" src="http://blog.andrewnurse.net/content/binary/WindowsLiveWriter/Windows7FirstImpressions_CD0A/image_thumb_3.png" width="298" height="131" /&gt;&lt;/a&gt; 
&lt;/p&gt;
&lt;h2&gt;
&lt;/h2&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
I haven’t had much of a chance to explore the rest of the new stuff, so I’ll post
more later, but my initial impression is that Windows 7 is just plain awesome :).
&lt;/p&gt;
&lt;img width="0" height="0" src="http://blog.andrewnurse.net/aggbug.ashx?id=a97379a1-ad74-4a0a-9a2f-e5784a03b891" /&gt;</description>
      <comments>http://blog.andrewnurse.net/CommentView,guid,a97379a1-ad74-4a0a-9a2f-e5784a03b891.aspx</comments>
      <category>CMPT 376</category>
      <category>Cool Software</category>
      <category>Windows 7</category>
    </item>
    <item>
      <trackback:ping>http://blog.andrewnurse.net/Trackback.aspx?guid=1969792d-8472-47ec-921e-72a202396ab0</trackback:ping>
      <pingback:server>http://blog.andrewnurse.net/pingback.aspx</pingback:server>
      <pingback:target>http://blog.andrewnurse.net/PermaLink,guid,1969792d-8472-47ec-921e-72a202396ab0.aspx</pingback:target>
      <dc:creator>Andrew Nurse</dc:creator>
      <wfw:comment>http://blog.andrewnurse.net/CommentView,guid,1969792d-8472-47ec-921e-72a202396ab0.aspx</wfw:comment>
      <wfw:commentRss>http://blog.andrewnurse.net/SyndicationService.asmx/GetEntryCommentsRss?guid=1969792d-8472-47ec-921e-72a202396ab0</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
One of the courses I took last semester (Fall 2008), was “Software Engineering II”. 
In this class, we were required to work in groups to implement a project that the
professor specified.  We had to go through the whole process, design, implementation,
testing (though we could choose any software process model we wanted: Waterfall, XP,
Agile, etc.).  Our group’s project was an application called “Mappr” that would
allow users to browse a map.  Well, it was a little more than that, but that’s
all the background required by this post, I’ll post more background in future posts.
</p>
        <p>
One of the necessary components in mapping software is called a “Projection”. 
The Earth is round, and Latitude and Longitude co-ordinates are spherical measurements
representing points on the Earth.  In order to convert those co-ordinates to
(x, y) co-ordinates for displaying on a (flat) computer screen, you must <em>project</em> the
geographical co-ordinates into screen co-ordinates.  One well-known technique
for doing this is called the <a href="http://en.wikipedia.org/wiki/Mercator_projection">Mercator
Projection</a>.
</p>
        <p>
A quick aside: The Mercator Projection is widely known (in geography circles) for
being highly inaccurate.  However, it is the projection used by most road maps,
atlases, etc., both physical and digital.
</p>
        <p>
In Mappr, projection is handled by a component called a “Projection Strategy”. 
A Projection Strategy is a C# class (Mappr was written in C#) with two methods: GeoToScreen
and ScreenToGeo.   Here are the signatures of those methods:
</p>
        <pre class="csharp" name="code">public interface IProjectionStrategy {
    Point GeoToScreen(Point geographicalPoint, int zoomLevel, int tileSize);
    Point ScreenToGeo(Point screenPoint, int zoomLevel, int tileSize);
}</pre>
        <p>
The purpose of each method is straight forward: To take in either Geographical (Latitude,
Longitude) co-ordinates or Screen (X, Y) co-ordinates, and convert them to the other. 
In order to do this, we must know the Zoom Level, which is an integer <em>N</em> indicating
that there are <em>2<sup>N</sup></em> tiles on the screen.  We also need the
size, in pixels, of each map tile image.  This means that the size of the map,
in pixels, is given by: <em>2<sup>zoomLevel</sup> * tileSize</em>.
</p>
        <p>
The code to <em>project</em> a geographical point on to the screen is shown below:
</p>
        <pre class="csharp" name="code">public Point GeoToScreen(Point geographicalPoint, int zoomLevel, int tileSize) {
    // Convert to normalized mercator
    double lon = geographicalPoint.X;
    double lat = geographicalPoint.Y;

    if (lon &gt; 180) {
        lon -= 360;
    }

    lon /= 360;
    lon += 0.5;

    lat = 0.5 - ((Math.Log(Math.Tan((Math.PI / 4) + 
                 ((0.5 * Math.PI * lat) / 180))) / Math.PI) / 2.0);

    double scale = (1 &lt;&lt; zoomLevel) * tileSize;
    return new Point(lon * scale, lat * scale);
}</pre>
        <p>
This code first normalizes the longitude (X direction) so that it is in the range
0.0 to 1.0 (where 0.0 is the left of the map and 1.0 is the right).  Then it
does what I like to call “mathy stuff” (the calculations are taken from <a href="http://mapki.com/wiki/Tile_utility_code_in_Java">similar
code written in Java</a>) with the latitude to put it in the same range (0.0 is the
top, 1.0 is the bottom).  Finally, we calculate the scale of the map (height/width
in pixels, since the map is technically a square) and then we can use the normalized
longitude and latitude as ratios of that scale.
</p>
        <p>
The ScreenToGeo method is similar, the code is below.  I won’t describe this,
but just provide it for reference.
</p>
        <pre class="csharp" name="code">public Point ScreenToGeo(Point screenPoint, int zoomLevel, int tileSize) {
    int pixelSpan = (1 &lt;&lt; zoomLevel) * tileSize;
    double lngWidth = 360.0 / pixelSpan; // width in degrees longitude
    double lng = -180 + (screenPoint.X * lngWidth); // left edge in degrees longitude

    double latHeightMerc = 1.0 / pixelSpan; // height in "normalized" mercator 0,0 top left
    double latMerc = screenPoint.Y * latHeightMerc; // top edge in "normalized" mercator 0,0 top left
    
    // convert top and bottom lat in mercator to degrees
    // note that in fact the coordinates go from about -85 to +85 not -90 to 90!
    double lat = (180 / Math.PI) * ((2 * Math.Atan(Math.Exp(Math.PI * (1 - (2 * latMerc)))))
                       - (Math.PI / 2));

    return new Point(lng, lat);
}</pre>
        <p>
By the way, feel free to use any of the code in this post in your own application.
Consider it "Public Domain". However, I would appreciate (but not require)
if you would place a comment near it indicating that this blog is the source of the
original code.
</p>
        <p>
Hopefully this helps those of you writing mapping applications in C#!  Please
post any questions or comments in the comments section!
</p>
        <img width="0" height="0" src="http://blog.andrewnurse.net/aggbug.ashx?id=1969792d-8472-47ec-921e-72a202396ab0" />
      </body>
      <title>Mappr: Projecting Geographical Points on the Screen</title>
      <guid isPermaLink="false">http://blog.andrewnurse.net/PermaLink,guid,1969792d-8472-47ec-921e-72a202396ab0.aspx</guid>
      <link>http://blog.andrewnurse.net/2009/01/09/MapprProjectingGeographicalPointsOnTheScreen.aspx</link>
      <pubDate>Fri, 09 Jan 2009 18:07:54 GMT</pubDate>
      <description>&lt;p&gt;
One of the courses I took last semester (Fall 2008), was “Software Engineering II”.&amp;#160;
In this class, we were required to work in groups to implement a project that the
professor specified.&amp;#160; We had to go through the whole process, design, implementation,
testing (though we could choose any software process model we wanted: Waterfall, XP,
Agile, etc.).&amp;#160; Our group’s project was an application called “Mappr” that would
allow users to browse a map.&amp;#160; Well, it was a little more than that, but that’s
all the background required by this post, I’ll post more background in future posts.
&lt;/p&gt;
&lt;p&gt;
One of the necessary components in mapping software is called a “Projection”.&amp;#160;
The Earth is round, and Latitude and Longitude co-ordinates are spherical measurements
representing points on the Earth.&amp;#160; In order to convert those co-ordinates to
(x, y) co-ordinates for displaying on a (flat) computer screen, you must &lt;em&gt;project&lt;/em&gt; the
geographical co-ordinates into screen co-ordinates.&amp;#160; One well-known technique
for doing this is called the &lt;a href="http://en.wikipedia.org/wiki/Mercator_projection"&gt;Mercator
Projection&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
A quick aside: The Mercator Projection is widely known (in geography circles) for
being highly inaccurate.&amp;#160; However, it is the projection used by most road maps,
atlases, etc., both physical and digital.
&lt;/p&gt;
&lt;p&gt;
In Mappr, projection is handled by a component called a “Projection Strategy”.&amp;#160;
A Projection Strategy is a C# class (Mappr was written in C#) with two methods: GeoToScreen
and ScreenToGeo.&amp;#160;&amp;#160; Here are the signatures of those methods:
&lt;/p&gt;
&lt;pre class="csharp" name="code"&gt;public interface IProjectionStrategy {
    Point GeoToScreen(Point geographicalPoint, int zoomLevel, int tileSize);
    Point ScreenToGeo(Point screenPoint, int zoomLevel, int tileSize);
}&lt;/pre&gt;
&lt;p&gt;
The purpose of each method is straight forward: To take in either Geographical (Latitude,
Longitude) co-ordinates or Screen (X, Y) co-ordinates, and convert them to the other.&amp;#160;
In order to do this, we must know the Zoom Level, which is an integer &lt;em&gt;N&lt;/em&gt; indicating
that there are &lt;em&gt;2&lt;sup&gt;N&lt;/sup&gt;&lt;/em&gt; tiles on the screen.&amp;#160; We also need the
size, in pixels, of each map tile image.&amp;#160; This means that the size of the map,
in pixels, is given by: &lt;em&gt;2&lt;sup&gt;zoomLevel&lt;/sup&gt; * tileSize&lt;/em&gt;.
&lt;/p&gt;
&lt;p&gt;
The code to &lt;em&gt;project&lt;/em&gt; a geographical point on to the screen is shown below:
&lt;/p&gt;
&lt;pre class="csharp" name="code"&gt;public Point GeoToScreen(Point geographicalPoint, int zoomLevel, int tileSize) {
    // Convert to normalized mercator
    double lon = geographicalPoint.X;
    double lat = geographicalPoint.Y;

    if (lon &amp;gt; 180) {
        lon -= 360;
    }

    lon /= 360;
    lon += 0.5;

    lat = 0.5 - ((Math.Log(Math.Tan((Math.PI / 4) + 
                 ((0.5 * Math.PI * lat) / 180))) / Math.PI) / 2.0);

    double scale = (1 &amp;lt;&amp;lt; zoomLevel) * tileSize;
    return new Point(lon * scale, lat * scale);
}&lt;/pre&gt;
&lt;p&gt;
This code first normalizes the longitude (X direction) so that it is in the range
0.0 to 1.0 (where 0.0 is the left of the map and 1.0 is the right).&amp;#160; Then it
does what I like to call “mathy stuff” (the calculations are taken from &lt;a href="http://mapki.com/wiki/Tile_utility_code_in_Java"&gt;similar
code written in Java&lt;/a&gt;) with the latitude to put it in the same range (0.0 is the
top, 1.0 is the bottom).&amp;#160; Finally, we calculate the scale of the map (height/width
in pixels, since the map is technically a square) and then we can use the normalized
longitude and latitude as ratios of that scale.
&lt;/p&gt;
&lt;p&gt;
The ScreenToGeo method is similar, the code is below.&amp;#160; I won’t describe this,
but just provide it for reference.
&lt;/p&gt;
&lt;pre class="csharp" name="code"&gt;public Point ScreenToGeo(Point screenPoint, int zoomLevel, int tileSize) {
    int pixelSpan = (1 &amp;lt;&amp;lt; zoomLevel) * tileSize;
    double lngWidth = 360.0 / pixelSpan; // width in degrees longitude
    double lng = -180 + (screenPoint.X * lngWidth); // left edge in degrees longitude

    double latHeightMerc = 1.0 / pixelSpan; // height in &amp;quot;normalized&amp;quot; mercator 0,0 top left
    double latMerc = screenPoint.Y * latHeightMerc; // top edge in &amp;quot;normalized&amp;quot; mercator 0,0 top left
    
    // convert top and bottom lat in mercator to degrees
    // note that in fact the coordinates go from about -85 to +85 not -90 to 90!
    double lat = (180 / Math.PI) * ((2 * Math.Atan(Math.Exp(Math.PI * (1 - (2 * latMerc)))))
                       - (Math.PI / 2));

    return new Point(lng, lat);
}&lt;/pre&gt;
&lt;p&gt;
By the way, feel free to use any of the code in this post in your own application.
Consider it &amp;quot;Public Domain&amp;quot;. However, I would appreciate (but not require)
if you would place a comment near it indicating that this blog is the source of the
original code.
&lt;/p&gt;
&lt;p&gt;
Hopefully this helps those of you writing mapping applications in C#!&amp;#160; Please
post any questions or comments in the comments section!
&lt;/p&gt;
&lt;img width="0" height="0" src="http://blog.andrewnurse.net/aggbug.ashx?id=1969792d-8472-47ec-921e-72a202396ab0" /&gt;</description>
      <comments>http://blog.andrewnurse.net/CommentView,guid,1969792d-8472-47ec-921e-72a202396ab0.aspx</comments>
      <category>CMPT 376</category>
      <category>Cool Software</category>
      <category>School</category>
    </item>
    <item>
      <trackback:ping>http://blog.andrewnurse.net/Trackback.aspx?guid=49360f6b-7347-4780-8cad-8cb25f1fd731</trackback:ping>
      <pingback:server>http://blog.andrewnurse.net/pingback.aspx</pingback:server>
      <pingback:target>http://blog.andrewnurse.net/PermaLink,guid,49360f6b-7347-4780-8cad-8cb25f1fd731.aspx</pingback:target>
      <dc:creator>Andrew Nurse</dc:creator>
      <wfw:comment>http://blog.andrewnurse.net/CommentView,guid,49360f6b-7347-4780-8cad-8cb25f1fd731.aspx</wfw:comment>
      <wfw:commentRss>http://blog.andrewnurse.net/SyndicationService.asmx/GetEntryCommentsRss?guid=49360f6b-7347-4780-8cad-8cb25f1fd731</wfw:commentRss>
      <slash:comments>2</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">So, I've started playing around with the
whole Azure Services Platform (http://www.azure.com), now that school's done :) and
I thought I'd blog about things I discover along the way.<br /><br />
My first idea was to create a simple blogging engine in MVC that would store data
in SQL Data Services and run in Windows Azure (I got my invite code recently, yay!). 
However, I soon discovered that would be difficult.  It turns out that while
SQL Data Services does support "Paging" the results of a query so that you don't retrieve
every result in one batch, it does not support what I refer to as "Random Access Paging". 
Random Access Paging (and I'm sure theres some other term for it) basically means
providing a page index and page size to the data layer and having it retrieve just
that page (i.e. Skip/Take in LINQ).  There are some solutions, but most of them
requrire that you step through each page sequentially, rather than just being able
to request a page.<br /><br />
Of course, I may be missing something. So, if you know how I could solve this problem,
feel free to post in the comments!<br /><br />
In a blogging engine, this is practically a necessity, since you only want to display
a certain number of posts per page.  So I've tabled that idea for now.<br /><br />
My next idea: An RSS reader which stores your set of subscribed feeds in your Live
Mesh (though I don't have access to that CTP yet).<br /><p></p><img width="0" height="0" src="http://blog.andrewnurse.net/aggbug.ashx?id=49360f6b-7347-4780-8cad-8cb25f1fd731" /></body>
      <title>Playing with Azure and SQL Data Services: No "Random Access Paging"</title>
      <guid isPermaLink="false">http://blog.andrewnurse.net/PermaLink,guid,49360f6b-7347-4780-8cad-8cb25f1fd731.aspx</guid>
      <link>http://blog.andrewnurse.net/2008/12/16/PlayingWithAzureAndSQLDataServicesNoRandomAccessPaging.aspx</link>
      <pubDate>Tue, 16 Dec 2008 21:20:31 GMT</pubDate>
      <description>So, I've started playing around with the whole Azure Services Platform (http://www.azure.com), now that school's done :) and I thought I'd blog about things I discover along the way.&lt;br&gt;
&lt;br&gt;
My first idea was to create a simple blogging engine in MVC that would store data
in SQL Data Services and run in Windows Azure (I got my invite code recently, yay!).&amp;nbsp;
However, I soon discovered that would be difficult.&amp;nbsp; It turns out that while
SQL Data Services does support "Paging" the results of a query so that you don't retrieve
every result in one batch, it does not support what I refer to as "Random Access Paging".&amp;nbsp;
Random Access Paging (and I'm sure theres some other term for it) basically means
providing a page index and page size to the data layer and having it retrieve just
that page (i.e. Skip/Take in LINQ).&amp;nbsp; There are some solutions, but most of them
requrire that you step through each page sequentially, rather than just being able
to request a page.&lt;br&gt;
&lt;br&gt;
Of course, I may be missing something. So, if you know how I could solve this problem,
feel free to post in the comments!&lt;br&gt;
&lt;br&gt;
In a blogging engine, this is practically a necessity, since you only want to display
a certain number of posts per page.&amp;nbsp; So I've tabled that idea for now.&lt;br&gt;
&lt;br&gt;
My next idea: An RSS reader which stores your set of subscribed feeds in your Live
Mesh (though I don't have access to that CTP yet).&lt;br&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://blog.andrewnurse.net/aggbug.ashx?id=49360f6b-7347-4780-8cad-8cb25f1fd731" /&gt;</description>
      <comments>http://blog.andrewnurse.net/CommentView,guid,49360f6b-7347-4780-8cad-8cb25f1fd731.aspx</comments>
      <category>Azure</category>
      <category>Cool Software</category>
      <category>MVC</category>
    </item>
    <item>
      <trackback:ping>http://blog.andrewnurse.net/Trackback.aspx?guid=9e40c7a1-5600-4545-9974-61e652528751</trackback:ping>
      <pingback:server>http://blog.andrewnurse.net/pingback.aspx</pingback:server>
      <pingback:target>http://blog.andrewnurse.net/PermaLink,guid,9e40c7a1-5600-4545-9974-61e652528751.aspx</pingback:target>
      <dc:creator>Andrew Nurse</dc:creator>
      <wfw:comment>http://blog.andrewnurse.net/CommentView,guid,9e40c7a1-5600-4545-9974-61e652528751.aspx</wfw:comment>
      <wfw:commentRss>http://blog.andrewnurse.net/SyndicationService.asmx/GetEntryCommentsRss?guid=9e40c7a1-5600-4545-9974-61e652528751</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
This is part 2 of my VidSpeak series, where I show off an app I wrote for my multimedia
course.  <a href="http://blog.andrewnurse.net/2008/10/21/VidSpeakPart1ExtractingFramesFromVideoInC.aspx">Check
out part 1</a>.
</p>
        <p>
To recap from last time, the problem this assignment is trying to solve is to convert
video frames to some kind of audio representation.  There are the steps required:
</p>
        <ol>
          <li>
Extract the next frame from the video 
</li>
          <li>
Scale the frame down to 64x64 pixels 
</li>
          <li>
Make the frame a grayscale image 
</li>
          <li>
"Quantize" the grayscale frame into 4-bit colour 
</li>
          <li>
Convert the frame to sound</li>
        </ol>
        <p>
I covered extracting video frames in Part 1, so now we have to manipulate the image
to prepare it for rendering as sound.
</p>
        <p>
          <strong>2. Scale the frame down to 64x64 pixels</strong>
        </p>
        <p>
All the transformation steps (2-4) are performed by "filters" which recieve a System.Drawing.Bitmap
and return a transformed one (a filter could also modify the incoming Bitmap and then
just return the same object).  Scaling is trivial with the "GetThumbnailImage"
method on System.Drawing.Image:
</p>
        <pre name="code" class="csharp">public Bitmap ProcessImage(Bitmap input) {
    return new Bitmap(input.GetThumbnailImage(TargetWidth, TargetHeight, null, IntPtr.Zero));
}
</pre>
        <p>
          <strong>3. Make the frame a grayscale image</strong>
        </p>
        <p>
There may be a function in .Net to do this, but as part of the assignment we were
provided with a formula to convert RGB images to 255-shade grayscale images so I decided
to do this.  Now, the Bitmap class provides GetPixel and SetPixel methods, but
they aren't really very performant when you need to touch every pixel.  Fortunately,
the Bitmap class provides a method called "LockPixels" which prevents the Garbage
Collector from moving the Bitmap data around in memory.  With that, I made a
base class for filters that process a Bitmap on a Pixel-by-Pixel basis:
</p>
        <pre name="code" class="csharp">
BitmapData data = input.LockBits(new Rectangle(0, 0, input.Width, input.Height), 
                                 ImageLockMode.ReadWrite, 
                                 PixelFormat.Format24bppRgb);
unsafe {
    for (int col = 0; col &lt; data.Width; col++) {
        for (int row = 0; row &lt; data.Height; row++) {
            PixelData* pixel = (PixelData*)data.Scan0 + col + row * data.Width;
            ProcessPixel(pixel);
        }
    }
}
input.UnlockBits(data);
</pre>
        <p>
PixelData is a simple 3-byte struct:
</p>
        <pre name="code" class="csharp">[StructLayout(LayoutKind.Sequential)]
public struct PixelData {
    public byte Blue;
    public byte Green;
    public byte Red;
}</pre>
        <p>
Then, my grayscale image filter just has to implement ProcessPixel
</p>
        <pre name="code" class="csharp">
byte convertedValue = (byte) Math.Floor((0.299 * pixel-&gt;Red) + 
                                        (0.587 * pixel-&gt;Green) + 
                                        (0.114 * pixel-&gt;Blue));
pixel-&gt;Red = convertedValue;
pixel-&gt;Green = convertedValue;
pixel-&gt;Blue = convertedValue;</pre>
        <p>
Kinda strange to see the "-&gt;" operator in C#, eh?
</p>
        <p>
4. "Quantize" the image to 4-bit colour
</p>
        <p>
Quantization is the process of "compressing a range of values to a single quantum
value" (<a href="http://en.wikipedia.org/wiki/Quantization_%28image_processing">http://en.wikipedia.org/wiki/Quantization_(image_processing</a>)). 
In this case, we are quantizing an 8-bit Grayscale image to a 4-bit Grayscale image. 
To do this, we take each pixel value, and assign it one of 16 partitions (4-bits can
hold values 0 through 15).  The following code (in FixedPartitionQuantizationStrategy)
does this (note _partitionSize is 16 in this case).
</p>
        <pre name="code" class="csharp">public byte Quantize(byte input) {
    return (byte)Math.Floor((double)input / _partitionSize);
}</pre>
        <p>
Quantization is done by the QuantizeImageFilter, which uses a similar base class to
the Grayscale conversion above.  Then, an IQuantizationStrategy is used to perform
the Quantization itself:
</p>
        <pre name="code" class="csharp">protected override unsafe void ProcessPixel(PixelData* pixel) {
    pixel-&gt;Red = _strategy.Quantize(pixel-&gt;Red);
    pixel-&gt;Green = _strategy.Quantize(pixel-&gt;Green);
    pixel-&gt;Blue = _strategy.Quantize(pixel-&gt;Blue);
}
</pre>
        <p>
And thats it! We now have an image that is 64x64 pixels in 4-bit Grayscale. 
Next we have to render it out to sound.  Stay tuned for Part 3 for that!
</p>
        <img width="0" height="0" src="http://blog.andrewnurse.net/aggbug.ashx?id=9e40c7a1-5600-4545-9974-61e652528751" />
      </body>
      <title>VidSpeak Part 2 - Bitmap Manipulation</title>
      <guid isPermaLink="false">http://blog.andrewnurse.net/PermaLink,guid,9e40c7a1-5600-4545-9974-61e652528751.aspx</guid>
      <link>http://blog.andrewnurse.net/2008/10/30/VidSpeakPart2BitmapManipulation.aspx</link>
      <pubDate>Thu, 30 Oct 2008 20:44:15 GMT</pubDate>
      <description>&lt;p&gt;
This is part 2 of my VidSpeak series, where I show off an app I wrote for my multimedia
course.&amp;nbsp; &lt;a href="http://blog.andrewnurse.net/2008/10/21/VidSpeakPart1ExtractingFramesFromVideoInC.aspx"&gt;Check
out part 1&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
To recap from last time, the problem this assignment is trying to solve is to convert
video frames to some kind of audio representation.&amp;nbsp; There are the steps required:
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Extract the next frame from the video 
&lt;/li&gt;
&lt;li&gt;
Scale the frame down to 64x64 pixels 
&lt;/li&gt;
&lt;li&gt;
Make the frame a grayscale image 
&lt;/li&gt;
&lt;li&gt;
"Quantize" the grayscale frame into 4-bit colour 
&lt;/li&gt;
&lt;li&gt;
Convert the frame to sound&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
I covered extracting video frames in Part 1, so now we have to manipulate the image
to prepare it for rendering as sound.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;2. Scale the frame down to 64x64 pixels&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
All the transformation steps (2-4) are performed by "filters" which recieve a System.Drawing.Bitmap
and return a transformed one (a filter could also modify the incoming Bitmap and then
just return the same object).&amp;nbsp; Scaling is trivial with the "GetThumbnailImage"
method on System.Drawing.Image:
&lt;/p&gt;
&lt;pre name="code" class="csharp"&gt;public Bitmap ProcessImage(Bitmap input) {
    return new Bitmap(input.GetThumbnailImage(TargetWidth, TargetHeight, null, IntPtr.Zero));
}
&lt;/pre&gt;
&lt;p&gt;
&lt;strong&gt;3. Make the frame a grayscale image&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
There may be a function in .Net to do this, but as part of the assignment we were
provided with a formula to convert RGB images to 255-shade grayscale images so I decided
to do this.&amp;nbsp; Now, the Bitmap class provides GetPixel and SetPixel methods, but
they aren't really very performant when you need to touch every pixel.&amp;nbsp; Fortunately,
the Bitmap class provides a method called "LockPixels" which prevents the Garbage
Collector from moving the Bitmap data around in memory.&amp;nbsp; With that, I made a
base class for filters that process a Bitmap on a Pixel-by-Pixel basis:
&lt;/p&gt;
&lt;pre name="code" class="csharp"&gt;
BitmapData data = input.LockBits(new Rectangle(0, 0, input.Width, input.Height), 
                                 ImageLockMode.ReadWrite, 
                                 PixelFormat.Format24bppRgb);
unsafe {
    for (int col = 0; col &amp;lt; data.Width; col++) {
        for (int row = 0; row &amp;lt; data.Height; row++) {
            PixelData* pixel = (PixelData*)data.Scan0 + col + row * data.Width;
            ProcessPixel(pixel);
        }
    }
}
input.UnlockBits(data);
&lt;/pre&gt;
&lt;p&gt;
PixelData is a simple 3-byte struct:
&lt;/p&gt;
&lt;pre name="code" class="csharp"&gt;[StructLayout(LayoutKind.Sequential)]
public struct PixelData {
    public byte Blue;
    public byte Green;
    public byte Red;
}&lt;/pre&gt;
&lt;p&gt;
Then, my grayscale image filter just has to implement ProcessPixel
&lt;/p&gt;
&lt;pre name="code" class="csharp"&gt;
byte convertedValue = (byte) Math.Floor((0.299 * pixel-&amp;gt;Red) + 
                                        (0.587 * pixel-&amp;gt;Green) + 
                                        (0.114 * pixel-&amp;gt;Blue));
pixel-&amp;gt;Red = convertedValue;
pixel-&amp;gt;Green = convertedValue;
pixel-&amp;gt;Blue = convertedValue;&lt;/pre&gt;
&lt;p&gt;
Kinda strange to see the "-&amp;gt;" operator in C#, eh?
&lt;/p&gt;
&lt;p&gt;
4. "Quantize" the image to 4-bit colour
&lt;/p&gt;
&lt;p&gt;
Quantization is the process of "compressing a range of values to a single quantum
value" (&lt;a href="http://en.wikipedia.org/wiki/Quantization_%28image_processing"&gt;http://en.wikipedia.org/wiki/Quantization_(image_processing&lt;/a&gt;)).&amp;nbsp;
In this case, we are quantizing an 8-bit Grayscale image to a 4-bit Grayscale image.&amp;nbsp;
To do this, we take each pixel value, and assign it one of 16 partitions (4-bits can
hold values 0 through 15).&amp;nbsp; The following code (in FixedPartitionQuantizationStrategy)
does this (note _partitionSize is 16 in this case).
&lt;/p&gt;
&lt;pre name="code" class="csharp"&gt;public byte Quantize(byte input) {
    return (byte)Math.Floor((double)input / _partitionSize);
}&lt;/pre&gt;
&lt;p&gt;
Quantization is done by the QuantizeImageFilter, which uses a similar base class to
the Grayscale conversion above.&amp;nbsp; Then, an IQuantizationStrategy is used to perform
the Quantization itself:
&lt;/p&gt;
&lt;pre name="code" class="csharp"&gt;protected override unsafe void ProcessPixel(PixelData* pixel) {
    pixel-&amp;gt;Red = _strategy.Quantize(pixel-&amp;gt;Red);
    pixel-&amp;gt;Green = _strategy.Quantize(pixel-&amp;gt;Green);
    pixel-&amp;gt;Blue = _strategy.Quantize(pixel-&amp;gt;Blue);
}
&lt;/pre&gt;
&lt;p&gt;
And thats it! We now have an image that is 64x64 pixels&amp;nbsp;in 4-bit Grayscale.&amp;nbsp;
Next we have to render it out to sound.&amp;nbsp; Stay tuned for Part 3 for that!
&lt;/p&gt;
&lt;img width="0" height="0" src="http://blog.andrewnurse.net/aggbug.ashx?id=9e40c7a1-5600-4545-9974-61e652528751" /&gt;</description>
      <comments>http://blog.andrewnurse.net/CommentView,guid,9e40c7a1-5600-4545-9974-61e652528751.aspx</comments>
      <category>Cool Software</category>
      <category>School</category>
    </item>
    <item>
      <trackback:ping>http://blog.andrewnurse.net/Trackback.aspx?guid=826fae58-1208-4af7-a4e4-2bbe01d855ca</trackback:ping>
      <pingback:server>http://blog.andrewnurse.net/pingback.aspx</pingback:server>
      <pingback:target>http://blog.andrewnurse.net/PermaLink,guid,826fae58-1208-4af7-a4e4-2bbe01d855ca.aspx</pingback:target>
      <dc:creator>Andrew Nurse</dc:creator>
      <wfw:comment>http://blog.andrewnurse.net/CommentView,guid,826fae58-1208-4af7-a4e4-2bbe01d855ca.aspx</wfw:comment>
      <wfw:commentRss>http://blog.andrewnurse.net/SyndicationService.asmx/GetEntryCommentsRss?guid=826fae58-1208-4af7-a4e4-2bbe01d855ca</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I know, its been too long since I blogged, but its pretty busy at school right now
:). Anyway, I'm taking a course in Multimedia this semester, and as part of that course,
I have to write a program to convert frames in a Video to short Audio clips. I
thought it might be interesting to examine how that is done, in C#.  So,
over the course of about 3-4 posts, I'll go over the code that I wrote.  I've
attached the full project to this post, so you can take a look at it right now. 
The GUI app should work, though I can't guarantee it. All I can give it is "Works
on My Machine" seal of approval :) 
</p>
        <p>
          <img src="http://www.codinghorror.com/blog/images/works-on-my-machine-starburst.png" />
        </p>
        <p>
        </p>
        <p>
Here are the steps involved:
</p>
        <ol>
          <li>
Extract the next frame from the video 
</li>
          <li>
Scale the frame down to 64x64 pixels 
</li>
          <li>
Make the frame a grayscale image 
</li>
          <li>
"Quantize" the grayscale frame into 4-bit colour 
</li>
          <li>
Convert the frame to sound</li>
        </ol>
        <h5>The Code
</h5>
        <p>
The Code is a Visual Studio 2008 solution, written for .Net 3.5.  It uses unsafe
code for image processing and sound generation, so you can't run it without full trust
(i.e. you can't run it off of a network share).
</p>
        <h5>1. Extract the next frame from the video
</h5>
        <p>
I used a "Pipeline" (<a href="http://en.wikipedia.org/wiki/Pipeline_%28software%29">http://en.wikipedia.org/wiki/Pipeline_(software)</a>)
architecture, so this phase is handled by a component I call a "Frame Source" which
is expected to return a new frame when asked (or return null to signal the end of
the input). I used the DirectShow COM library "<a href="http://msdn.microsoft.com/en-us/library/ms783323.aspx">DexterLib</a>"
to do the extraction. DexterLib contains a class called MediaDet (for MediaDetector)
which does most of the work. Here's the code for the function which retrieves a frame
at a specified timecode (in seconds).  
</p>
        <p>
FYI: "_detector" is an instance of DexterLib.MediaDetClass() ("_detector" is of type
IMediaDet), "_streamLength" is the length of of the video stream in seconds, "_bufferHandle"
is an IntPtr referring to an unmanaged buffer (allocated with Marshal.AllocHGlobal)
to hold the bitmap, and "_bufferSize"/"_frameSize" are the size of the buffer and
the size of each video frame (respectively)
</p>
        <pre name="code" class="csharp">// WARNING: This method will destroy the bitmap retrieved in a previous call to this method
public Bitmap GetFrameAtTime(double timeCode) {
    // Get the bitmap at this time
    Bitmap frame = null;
    unsafe {
        byte* bufferPointer = (byte*)_bufferHandle;
        _detector.GetBitmapBits(timeCode, 
                                ref _bufferSize, 
                                ref *bufferPointer, 
                                _frameSize.Width, 
                                _frameSize.Height);
        frame = new Bitmap(_frameSize.Width, // Width
                           _frameSize.Height, // Heigth
                           _frameSize.Width * 3, // Stride
                           PixelFormat.Format24bppRgb, // Pixel Format
                           new IntPtr(bufferPointer + 
                                      Marshal.SizeOf(typeof(BITMAPINFOHEADER)))); // Start of Buffer
    }

    return frame;
}</pre>
        <p>
(Note: If you look at the actualy code, you will notice I snipped out some stuff from
the beginning of this function to display it on the blog. The missing code just
handles an (experimental) feature I added to allow me to start at any location in
the video, rather than always starting at the beginning)
</p>
        <p>
After loading the frame, I have to flip it, because Dexter loads the frame upside-down,
fortunately the System.Drawing.Image class provides a RotateFlip method to do just
that! I also rotate it 90 degrees clock-wise, so that each row of the transformed
image maps to a column of the frame. This makes step 5 easier, since Bitmaps are stored
in "row-major" order (<a href="http://en.wikipedia.org/wiki/Row-major_order">http://en.wikipedia.org/wiki/Row-major_order</a>).
</p>
        <p>
To use the Frame Source, all my program has to do is call GetFrameAtTime method passing
in a timecode (in seconds).  This is handled in the FrameProcessor by the GetNextFrame
method
</p>
        <pre name="code" class="csharp">_source.GetFrameAtTime((DateTime.Now - _startTime).TotalSeconds)</pre>
        <p>
Rather than going frame-by-frame, I'm extracting the next frame by time.  So,
if it takes 4 seconds to process a frame, the next frame I take is approximately 4
seconds after the frame I just processed.
</p>
        <p>
Here's the code: <a href="http://blog.andrewnurse.net/content/binary/VidSpeak.zip">VidSpeak.zip
(267.21 KB)</a></p>
        <img width="0" height="0" src="http://blog.andrewnurse.net/aggbug.ashx?id=826fae58-1208-4af7-a4e4-2bbe01d855ca" />
      </body>
      <title>VidSpeak Part 1 - Extracting Frames from Video in C#!</title>
      <guid isPermaLink="false">http://blog.andrewnurse.net/PermaLink,guid,826fae58-1208-4af7-a4e4-2bbe01d855ca.aspx</guid>
      <link>http://blog.andrewnurse.net/2008/10/21/VidSpeakPart1ExtractingFramesFromVideoInC.aspx</link>
      <pubDate>Tue, 21 Oct 2008 20:39:44 GMT</pubDate>
      <description>&lt;p&gt;
I know, its been too long since I blogged, but its pretty busy at school right now
:). Anyway, I'm taking a course in Multimedia this semester, and as part of that course,
I have to write a program to convert frames in a Video to short Audio clips.&amp;nbsp;I
thought it might&amp;nbsp;be interesting to examine how that is done, in C#.&amp;nbsp; So,
over the course of about 3-4 posts, I'll go over the code that I wrote.&amp;nbsp; I've
attached the full project to this post, so you can take a look at it right now.&amp;nbsp;
The GUI app should work, though I can't guarantee it. All I can give it is "Works
on My Machine" seal of approval :)&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.codinghorror.com/blog/images/works-on-my-machine-starburst.png"&gt; 
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
Here are the steps involved:
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Extract the next frame from the video 
&lt;/li&gt;
&lt;li&gt;
Scale the frame down to 64x64 pixels 
&lt;/li&gt;
&lt;li&gt;
Make the frame a grayscale image 
&lt;/li&gt;
&lt;li&gt;
"Quantize" the grayscale frame into 4-bit colour 
&lt;/li&gt;
&lt;li&gt;
Convert the frame to sound&lt;/li&gt;
&lt;/ol&gt;
&lt;h5&gt;The Code
&lt;/h5&gt;
&lt;p&gt;
The Code is a Visual Studio 2008 solution, written for .Net 3.5.&amp;nbsp; It uses unsafe
code for image processing and sound generation, so you can't run it without full trust
(i.e. you can't run it off of a network share).
&lt;/p&gt;
&lt;h5&gt;1. Extract the next frame from the video
&lt;/h5&gt;
&lt;p&gt;
I used a "Pipeline" (&lt;a href="http://en.wikipedia.org/wiki/Pipeline_%28software%29"&gt;http://en.wikipedia.org/wiki/Pipeline_(software)&lt;/a&gt;)
architecture, so this phase is handled by a component I call a "Frame Source" which
is expected to return a new frame when asked (or return null to signal the end of
the input). I used the DirectShow COM library "&lt;a href="http://msdn.microsoft.com/en-us/library/ms783323.aspx"&gt;DexterLib&lt;/a&gt;"
to do the extraction. DexterLib contains a class called MediaDet (for MediaDetector)
which does most of the work. Here's the code for the function which retrieves a frame
at a specified timecode (in seconds).&amp;nbsp; 
&lt;/p&gt;
&lt;p&gt;
FYI: "_detector" is an instance of DexterLib.MediaDetClass() ("_detector" is of type
IMediaDet), "_streamLength" is the length of of the video stream in seconds, "_bufferHandle"
is an IntPtr referring to an unmanaged buffer (allocated with Marshal.AllocHGlobal)
to hold the bitmap, and "_bufferSize"/"_frameSize" are the size of the buffer and
the size of each video frame (respectively)
&lt;/p&gt;
&lt;pre name="code" class="csharp"&gt;// WARNING: This method will destroy the bitmap retrieved in a previous call to this method
public Bitmap GetFrameAtTime(double timeCode) {
    // Get the bitmap at this time
    Bitmap frame = null;
    unsafe {
        byte* bufferPointer = (byte*)_bufferHandle;
        _detector.GetBitmapBits(timeCode, 
                                ref _bufferSize, 
                                ref *bufferPointer, 
                                _frameSize.Width, 
                                _frameSize.Height);
        frame = new Bitmap(_frameSize.Width, // Width
                           _frameSize.Height, // Heigth
                           _frameSize.Width * 3, // Stride
                           PixelFormat.Format24bppRgb, // Pixel Format
                           new IntPtr(bufferPointer + 
                                      Marshal.SizeOf(typeof(BITMAPINFOHEADER)))); // Start of Buffer
    }

    return frame;
}&lt;/pre&gt;
&lt;p&gt;
(Note: If you look at the actualy code, you will notice I snipped out some stuff from
the beginning of this function to display it on the blog.&amp;nbsp;The missing code just
handles an (experimental) feature I added to allow me to start at any location in
the video, rather than always starting at the beginning)
&lt;/p&gt;
&lt;p&gt;
After loading the frame, I have to flip it, because Dexter loads the frame upside-down,
fortunately the System.Drawing.Image class provides a RotateFlip method to do just
that! I also rotate it 90 degrees clock-wise, so that each row of the transformed
image maps to a column of the frame. This makes step 5 easier, since Bitmaps are stored
in "row-major" order (&lt;a href="http://en.wikipedia.org/wiki/Row-major_order"&gt;http://en.wikipedia.org/wiki/Row-major_order&lt;/a&gt;).
&lt;/p&gt;
&lt;p&gt;
To use the Frame Source, all my program has to do is call GetFrameAtTime method passing
in a timecode (in seconds).&amp;nbsp; This is handled in the FrameProcessor by the GetNextFrame
method
&lt;/p&gt;
&lt;pre name="code" class="csharp"&gt;_source.GetFrameAtTime((DateTime.Now - _startTime).TotalSeconds)&lt;/pre&gt;
&lt;p&gt;
Rather than going frame-by-frame, I'm extracting the next frame by time.&amp;nbsp; So,
if it takes 4 seconds to process a frame, the next frame I take is approximately 4
seconds after the frame I just processed.
&lt;/p&gt;
&lt;p&gt;
Here's the code: &lt;a href="http://blog.andrewnurse.net/content/binary/VidSpeak.zip"&gt;VidSpeak.zip
(267.21 KB)&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://blog.andrewnurse.net/aggbug.ashx?id=826fae58-1208-4af7-a4e4-2bbe01d855ca" /&gt;</description>
      <comments>http://blog.andrewnurse.net/CommentView,guid,826fae58-1208-4af7-a4e4-2bbe01d855ca.aspx</comments>
      <category>Cool Software</category>
      <category>School</category>
    </item>
    <item>
      <trackback:ping>http://blog.andrewnurse.net/Trackback.aspx?guid=538b858e-525e-4a21-9997-c5fc45d72007</trackback:ping>
      <pingback:server>http://blog.andrewnurse.net/pingback.aspx</pingback:server>
      <pingback:target>http://blog.andrewnurse.net/PermaLink,guid,538b858e-525e-4a21-9997-c5fc45d72007.aspx</pingback:target>
      <dc:creator>Andrew Nurse</dc:creator>
      <wfw:comment>http://blog.andrewnurse.net/CommentView,guid,538b858e-525e-4a21-9997-c5fc45d72007.aspx</wfw:comment>
      <wfw:commentRss>http://blog.andrewnurse.net/SyndicationService.asmx/GetEntryCommentsRss?guid=538b858e-525e-4a21-9997-c5fc45d72007</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Just writing a test post from Windows Live Writer. Look for a future, more detailed
post about it!
</p>
        <p>
        </p>
        <p>
        </p>
        <div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:98cda58e-fadb-4b8c-a9aa-31e395767057" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px">Technorati
Tags: <a href="http://technorati.com/tags/Windows%20Live%20Writer" rel="tag">Windows
Live Writer</a></div>
        <p>
        </p>
        <p>
Here's a map!
</p>
        <p>
        </p>
        <div class="wlWriterSmartContent" id="scid:84E294D0-71C9-4bd0-A0FE-95764E0368D9:0fda3bb5-6e57-49a7-b94a-bdc3a10a86b6" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px">
          <a href="http://maps.live.com/default.aspx?v=2&amp;cp=44.59047~-26.71875&amp;lvl=1&amp;style=r&amp;mkt=en-US&amp;FORM=LLWR" id="map-82044d76-d63c-4c16-a911-52f1671db2ef" alt="Click to view this map on Live.com" title="Click to view this map on Live.com">
            <img src="http://blog.andrewnurse.net/content/binary/WindowsLiveWriter/TestPostfromWindowsLiveWriter_14D5C/map-350854983f6b.jpg" width="320" height="240" alt="Map image" />
          </a>
        </div>
        <p>
        </p>
        <p>
ooo...fancy...
</p>
        <img width="0" height="0" src="http://blog.andrewnurse.net/aggbug.ashx?id=538b858e-525e-4a21-9997-c5fc45d72007" />
      </body>
      <title>Test Post from Windows Live Writer</title>
      <guid isPermaLink="false">http://blog.andrewnurse.net/PermaLink,guid,538b858e-525e-4a21-9997-c5fc45d72007.aspx</guid>
      <link>http://blog.andrewnurse.net/2007/11/20/TestPostFromWindowsLiveWriter.aspx</link>
      <pubDate>Tue, 20 Nov 2007 14:41:33 GMT</pubDate>
      <description>&lt;p&gt;
Just writing a test post from Windows Live Writer. Look for a future, more detailed
post about it!
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:98cda58e-fadb-4b8c-a9aa-31e395767057" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Technorati
Tags: &lt;a href="http://technorati.com/tags/Windows%20Live%20Writer" rel="tag"&gt;Windows
Live Writer&lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
Here's a map!
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;div class="wlWriterSmartContent" id="scid:84E294D0-71C9-4bd0-A0FE-95764E0368D9:0fda3bb5-6e57-49a7-b94a-bdc3a10a86b6" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;&lt;a href="http://maps.live.com/default.aspx?v=2&amp;amp;cp=44.59047~-26.71875&amp;amp;lvl=1&amp;amp;style=r&amp;amp;mkt=en-US&amp;amp;FORM=LLWR" id="map-82044d76-d63c-4c16-a911-52f1671db2ef" alt="Click to view this map on Live.com" title="Click to view this map on Live.com"&gt;&lt;img src="http://blog.andrewnurse.net/content/binary/WindowsLiveWriter/TestPostfromWindowsLiveWriter_14D5C/map-350854983f6b.jpg" width="320" height="240" alt="Map image"&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
ooo...fancy...
&lt;/p&gt;
&lt;img width="0" height="0" src="http://blog.andrewnurse.net/aggbug.ashx?id=538b858e-525e-4a21-9997-c5fc45d72007" /&gt;</description>
      <comments>http://blog.andrewnurse.net/CommentView,guid,538b858e-525e-4a21-9997-c5fc45d72007.aspx</comments>
      <category>Cool Software</category>
      <category>Random Stuff</category>
    </item>
  </channel>
</rss>