<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:copyright="http://blogs.law.harvard.edu/tech/rss" xmlns:image="http://purl.org/rss/1.0/modules/image/">
    <channel>
        <title>.NET</title>
        <link>http://www.jasonfollas.com/blog/category/5.aspx</link>
        <description>.NET</description>
        <language>en-US</language>
        <copyright>Jason Follas</copyright>
        <managingEditor>jason@jasonfollas.com</managingEditor>
        <generator>Subtext Version 2.0.0.43</generator>
        <item>
            <title>Windows Azure platform AppFabric Access Control: Introduction</title>
            <link>http://jasonfollas.com/blog/archive/2010/03/08/windows-azure-platform-appfabric-access-control-overview.aspx</link>
            <description>&lt;p&gt;  &lt;/p&gt;
&lt;p&gt;The &lt;a target="_blank" href="http://www.microsoft.com/windowsazure/appfabric/"&gt;Windows Azure platform AppFabric&lt;/a&gt; &lt;a target="_blank" href="http://msdn.microsoft.com/en-us/library/ee732536.aspx"&gt;Access Control&lt;/a&gt; service was one aspect of the &lt;a target="_blank" href="http://www.microsoft.com/windowsazure/"&gt;Windows Azure&lt;/a&gt; platform that I found a bit challenging to understand, primarily because identity is not a domain that I regularly work with.  This post, the first in a planned series of articles, will explore what the Access Control service is and why it is useful.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h3&gt;Three Geeks Walk Into a Bar…&lt;/h3&gt;
&lt;p&gt;&lt;a href="http://jasonfollas.com/blog/images/jasonfollas_com/blog/WindowsLiveWriter/WindowsAzureAccessControlService_11534/nightclub_access_control_8.png"&gt;&lt;img height="281" width="340" border="0" align="right" src="http://jasonfollas.com/blog/images/jasonfollas_com/blog/WindowsLiveWriter/WindowsAzureAccessControlService_11534/nightclub_access_control_thumb_2.png" alt="nightclub_access_control" title="nightclub_access_control" style="border-width: 0px; display: inline; margin-left: 0px; margin-right: 0px;" /&gt;&lt;/a&gt;Let’s examine a common real-world scenario: Ordering a drink from a bartender at a nightclub.&lt;/p&gt;
&lt;p&gt;Before the nightclub opens, the bouncers inform the bartenders about the token that customers will bear on that night to indicate that they are of legal age.  This could be a stamp on the back of the hand, a colored wristband, etc.&lt;/p&gt;
&lt;p&gt;At the door, a customer will present their identification to the bouncer that shows, among other things, their date of birth.  This ID could be a state-issued driver's license, a passport, or even a school identification card.  The point is that the nightclub didn’t issue that ID, but they recognize the authority that did issue it, and will accept the claim (the birth date) that is displayed on that ID.&lt;/p&gt;
&lt;p&gt;If the bouncer determines that the ID is authentic and hasn’t been tampered with, then he will give the customer the token of the night (stamped hand or colored wristband), and the customer is free to enter the bar.&lt;/p&gt;
&lt;p&gt;Once inside, the customer only needs to show the token to the bartender in order to buy drinks.  They do not need to show their ID.&lt;/p&gt;
&lt;p&gt;The next night, the token will change, so a customer cannot use a token obtained the night before.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h3&gt;Federated Access Control&lt;/h3&gt;
&lt;p&gt;&lt;a href="http://jasonfollas.com/blog/images/jasonfollas_com/blog/WindowsLiveWriter/WindowsAzureAccessControlService_11534/Azure_access_control_5.png"&gt;&lt;img height="189" width="340" border="0" align="right" src="http://jasonfollas.com/blog/images/jasonfollas_com/blog/WindowsLiveWriter/WindowsAzureAccessControlService_11534/Azure_access_control_thumb_1.png" alt="Azure_access_control" title="Azure_access_control" style="border-width: 0px; display: inline; margin-left: 0px; margin-right: 0px;" /&gt;&lt;/a&gt; Now let’s look at a similar scenario: Calling a web service from an application.  Only, in this case, the web service should not fulfill requests from unauthorized clients.  Furthermore, it’s not the web service’s responsibility to authenticate the client; it is simply expecting the client to bear some verifiable proof that it is already authorized to use the service.&lt;/p&gt;
&lt;p&gt;Before calling the Web Service, the Service Consumer (application) must first obtain a token that is issued by an Access Control Service (ACS).  This is done by sending a number of claims to the ACS, with one of these claims being secrets belonging to an Issuer that the application is associated with.  &lt;/p&gt;
&lt;p&gt;If the Issuer is recognized and trusted by the ACS, then a token will be created.  This token (which is a collection of name/value pairs) will contain claims, an expiration date, and a signature that can be used to ensure that the token was not modified after it was created.&lt;/p&gt;
&lt;p&gt;Once the Service Consumer has a valid token, it can then call the Web Service and provide that token in a location where the service expects to find it, such as in a HTTP header.  The Web Service validates that the token is well-formed, has not expired, and has not been modified since it was created.  If anything fails validation, then the processing aborts.  Otherwise, the web service returns data to the Service Consumer, possibly using claims contained in the token as input in the process.&lt;/p&gt;
&lt;p&gt;This scenario is considered to be Federated because the ACS doesn’t actually maintain a list of usernames and passwords.  Instead, it maintains a list of trusted Issuers with the expectation is that the Issuer is responsible for authenticating its own users.  &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h3&gt;Correlation&lt;/h3&gt;
&lt;p&gt;In these examples, the Web Service is analogous to the nightclub’s Bartender: it has something to provide to the Service Consumer (Customer), but the Service Consumer must present an appropriate token that is generated by the Access Control Service (Bouncer).&lt;/p&gt;
&lt;p&gt;The web service example above is intentionally vague in the part where a token is obtained.  There are a few different ways that an Issuer can be identified in a token request, and while passing the Issuer’s secret in plain text is one of those ways, it certainly shouldn’t be taken lightly.  Whoever has the Issuer’s key can spoof any of the claims, and that might prove to be a challenge for the service.  In the example where we need a Date of Birth claim to be presented, it would probably be a bad idea to allow the customer themselves to say “I’m from Ohio, here’s a blank driver's license that meets all of the standards of a proper ID, and, oh yeah… I’m writing on here that I am 21 years old.”  &lt;/p&gt;
&lt;p&gt;Instead, claims should originate from the Issuer in some way that cannot be tampered with by the application (using the assumption that the application itself should not be trusted).  With the plain text method, this might require having a separate service that runs within the Issuer’s domain and is aware of its users and also ACS.  This service would broker the ACS token request for the application, automatically providing any claim data that might be needed (like the Date of Birth) from the Issuer’s own user database.  The application would be provided with the same token, but would never have the Issuer’s secret that is required to obtain the token directly from ACS.&lt;/p&gt;&lt;img src="http://jasonfollas.com/blog/aggbug/77.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jason Follas</dc:creator>
            <guid>http://jasonfollas.com/blog/archive/2010/03/08/windows-azure-platform-appfabric-access-control-overview.aspx</guid>
            <pubDate>Tue, 09 Mar 2010 04:37:43 GMT</pubDate>
            <wfw:comment>http://jasonfollas.com/blog/comments/77.aspx</wfw:comment>
            <comments>http://jasonfollas.com/blog/archive/2010/03/08/windows-azure-platform-appfabric-access-control-overview.aspx#feedback</comments>
            <wfw:commentRss>http://jasonfollas.com/blog/comments/commentRss/77.aspx</wfw:commentRss>
            <trackback:ping>http://jasonfollas.com/blog/services/trackbacks/77.aspx</trackback:ping>
        </item>
        <item>
            <title>You Need that Using Statement for Extension Methods!</title>
            <link>http://jasonfollas.com/blog/archive/2010/02/25/you-need-that-using-statement-for-extension-methods.aspx</link>
            <description>I was working through some &lt;a href="javascript:void(0);/*1267124492396*/"&gt;Windows Azure&lt;/a&gt; example code today, and came across a situation where IntelliSense did not show a method that the sample code used (&lt;span style="font-family: Courier New;"&gt;CreateCloudBlobClient()&lt;/span&gt;, in this case):&lt;br /&gt;
&lt;br /&gt;
&lt;pre type="c-sharp" name="code"&gt;var storageAccount = Microsoft.WindowsAzure.CloudStorageAccount.FromConfigurationSetting("DataConnectionString");&lt;br /&gt;var blobStorage = storageAccount.CreateCloudBlobClient();&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;
A lot of times, when I'm exploring an API, I will type out the fully qualified class name in code so that I can use IntelliSense to see what the other members exist in the same namespace.  And, while I'm exploring, I usually don't bother to include a &lt;span style="font-family: Courier New;"&gt;using &lt;/span&gt;statement at the top of my code because it's so easy to just use the "Remove Type Qualifier" refactoring available in &lt;a target="_blank" href="http://devexpress.com/Products/Visual_Studio_Add-in/Coding_Assistance/"&gt;CodeRush&lt;/a&gt; to clean up the code when I'm ready to move on.&lt;br /&gt;
&lt;br /&gt;
Well, something that I guess I didn't remember soon enough was that &lt;span style="font-family: Courier New;"&gt;using &lt;/span&gt;statements are required in order to enable Extension Methods belonging to that namespace.  In this case, &lt;span style="font-family: Courier New;"&gt;CreateClousBlobClient() &lt;/span&gt;was not a method of&lt;span style="font-family: Courier New;"&gt; CloudStorageAccount&lt;/span&gt;, but rather an Extension Method (and this fact is not something that is very apparent when typing in sample code that you find in a document).&lt;br /&gt;
&lt;br /&gt;
IntelliSense showed that method (and more!) after adding the following line of code to the top of my file:&lt;br /&gt;
&lt;br /&gt;
&lt;pre type="c-sharp" name="code"&gt;using Microsoft.WindowsAzure.StorageClient;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;img src="http://jasonfollas.com/blog/aggbug/75.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jason Follas</dc:creator>
            <guid>http://jasonfollas.com/blog/archive/2010/02/25/you-need-that-using-statement-for-extension-methods.aspx</guid>
            <pubDate>Thu, 25 Feb 2010 19:11:38 GMT</pubDate>
            <comments>http://jasonfollas.com/blog/archive/2010/02/25/you-need-that-using-statement-for-extension-methods.aspx#feedback</comments>
            <wfw:commentRss>http://jasonfollas.com/blog/comments/commentRss/75.aspx</wfw:commentRss>
            <trackback:ping>http://jasonfollas.com/blog/services/trackbacks/75.aspx</trackback:ping>
        </item>
        <item>
            <title>Microsoft Solver Foundation</title>
            <link>http://jasonfollas.com/blog/archive/2009/04/04/microsoft-solver-foundation.aspx</link>
            <description>&lt;p&gt;&lt;strong&gt;Warning: Only 3 people who read this may actually understand it.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This morning, after actually considering what the effort might be to port lp_solve from C over to .NET, I stumbled upon this:&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;&lt;a href="http://code.msdn.microsoft.com/solverfoundation"&gt;http://code.msdn.microsoft.com/solverfoundation&lt;/a&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;About 4-5 years ago, I worked on a project that used a Frankenstein'ed "lp_solve 2.0-ported-to-Java-then-ported-to-C#" solver, which was great because it was free and it was a completely managed solution (no native components).  What I was doing wasn't particularly that heavy of a problem, but still required a solver to quickly and reliably minimize a cost given a bunch of user-provided constraints.&lt;/p&gt;
&lt;p&gt;Solver Foundation appears to satisfy both of these "requirements" (i.e., being Free and being completely managed).&lt;/p&gt;
&lt;p&gt;Now, if I can build a Silverlight 2.0+ app that is able to use MSF, then I essentially get infinite scaleout of my optimizer without requiring infinite server infrastructure.  &amp;lt;evil laugh&amp;gt;&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;&lt;img src="http://jasonfollas.com/blog/aggbug/68.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jason Follas</dc:creator>
            <guid>http://jasonfollas.com/blog/archive/2009/04/04/microsoft-solver-foundation.aspx</guid>
            <pubDate>Sat, 04 Apr 2009 11:53:21 GMT</pubDate>
            <comments>http://jasonfollas.com/blog/archive/2009/04/04/microsoft-solver-foundation.aspx#feedback</comments>
            <wfw:commentRss>http://jasonfollas.com/blog/comments/commentRss/68.aspx</wfw:commentRss>
            <trackback:ping>http://jasonfollas.com/blog/services/trackbacks/68.aspx</trackback:ping>
        </item>
        <item>
            <title>Enterprise ASP.NET Application Performance Tip</title>
            <link>http://jasonfollas.com/blog/archive/2009/02/23/enterprise-asp.net-application-performance-tip.aspx</link>
            <description>&lt;p&gt;&lt;a target="_blank" href="http://www.theregion.com/"&gt;Microsoft Regional Director&lt;/a&gt; (and friend) &lt;a target="_blank" href="http://stevesmithblog.com/"&gt;Steven Smith&lt;/a&gt; has a great talk about ASP.NET performance tips - I've seen the presentation probably a handful of times already, and always seem to walk away with something new to try that I didn't quite "grok" previously.  &lt;/p&gt;
&lt;p&gt;But, here's one additional tip that I can offer that is easily overlooked, yet very important for enterprise development.&lt;/p&gt;
&lt;p&gt;Enterprise web applications (at least in my world) tend to use Integrated Security in order to provide Single Sign-On capability (i.e., automatically authenticating the user according to their Active Directory credentials).  As such, Anonymous access to the web application is usually disabled directly in the metabase using the IIS MMC.  But, with sites that use a lot of small images, there's a serious performance hit that you take when Anonymous access is disabled!&lt;/p&gt;
&lt;p&gt;A web browser will always try to submit a request anonymously.  In the case that I described where Anonymous access is disabled, the web server will generate a 403 response (and include a list of possible ways that the client can authenticate itself).  The web browser will then either prompt the user for credentials, or in the case of using Internet Explorer in the Intranet Zone with an application protected by Integrated Security, will automatically provide a response to the NTLM challenge.  The point being that it takes two separate requests for each resource (not to mention a higher computational cost, since there's a challenge/response included).  Multiply this by however many little images your page might have, and your load time increases significantly.&lt;/p&gt;
&lt;p&gt;Just today, I was asked to diagnose a load-time issue for a 3rd party web application that my client uses.  The site looks nice because it uses little images all over the place - to the effect of hundreds per page!  But, the price of these aesthetics was really aweful load times, especially over a VPN connection.&lt;/p&gt;
&lt;p&gt;For images and other resources that do not necessarily need authentication, you can get an immediate performance improvement by enabling Anonymous access to the resource directories/files themselves (leaving Anonymous access disabled for the rest of the application).  &lt;/p&gt;&lt;img src="http://jasonfollas.com/blog/aggbug/64.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jason Follas</dc:creator>
            <guid>http://jasonfollas.com/blog/archive/2009/02/23/enterprise-asp.net-application-performance-tip.aspx</guid>
            <pubDate>Mon, 23 Feb 2009 19:15:00 GMT</pubDate>
            <comments>http://jasonfollas.com/blog/archive/2009/02/23/enterprise-asp.net-application-performance-tip.aspx#feedback</comments>
            <wfw:commentRss>http://jasonfollas.com/blog/comments/commentRss/64.aspx</wfw:commentRss>
            <trackback:ping>http://jasonfollas.com/blog/services/trackbacks/64.aspx</trackback:ping>
        </item>
        <item>
            <title>Using SQL Server Spatial Objects as ADO.NET Parameter Values</title>
            <link>http://jasonfollas.com/blog/archive/2008/12/11/using-ado.net-with-sql-server-spatial-objects.aspx</link>
            <description>&lt;p&gt;I've &lt;a target="_blank" href="http://jasonfollas.com/blog/archive/2008/06/23/sql-server-2008-spatial-data-part-8.aspx"&gt;previously mentioned&lt;/a&gt; that the SQL Server 2008 Spatial data types are freely available for use in your .NET applications, regardless of whether you have SQL Server 2008 or not.  This allows you to incorporate some powerful spatial capabilities right into your application.  &lt;/p&gt;
&lt;p&gt;&lt;em&gt;(Look for "&lt;font face="Arial"&gt;Microsoft SQL Server System CLR Types" on this page: &lt;font face="Arial"&gt;&lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=228DE03F-3B5A-428A-923F-58A033D316E1&amp;amp;displaylang=en"&gt;http://www.microsoft.com/downloads/details.aspx?FamilyID=228DE03F-3B5A-428A-923F-58A033D316E1&amp;amp;displaylang=en&lt;/a&gt; )&lt;/font&gt;&lt;/font&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;However, in most usage scenarios, there will come a time when you have an instance of a SQL Server spatial object in your .NET application, and need to commit it to your SQL Server 2008 database.  How would you do this, without losing fidelity or resorting to serialization of the object to WKT first?&lt;/p&gt;
&lt;p&gt;The solutions is to create a Parameter object of type System.Data.SqlDbType.Udt.  Then set the UdtTypeName parameter to the SQL Server-recognized type name (i.e., for SqlGeometry, you would simply use Geometry).&lt;/p&gt;
&lt;p&gt;The following code demonstrates executing an UPDATE statement that sets the value of a Spatial field to a newly constructed object.&lt;/p&gt;
&lt;pre class="c#" name="code"&gt;using (SqlConnection conn = new SqlConnection("Server=.;Integrated Security=true;Initial Catalog=scratch"))
{
   using (SqlCommand cmd = new SqlCommand("UPDATE fe_2007_us_zcta500 SET Boundary=@boundary WHERE id=@id", conn))
   {
      SqlParameter id = cmd.Parameters.Add("@id", System.Data.SqlDbType.Int);

      SqlParameter boundary = cmd.Parameters.Add("@boundary", System.Data.SqlDbType.Udt);
      boundary.UdtTypeName = "geometry";

      SqlGeometry geom = SqlGeometry.Parse("POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))");
      
      boundary.Value = geom;
      id.Value = 123;

      conn.Open();
      cmd.ExecuteNonQuery();
      conn.Close();
   }
}
&lt;/pre&gt;&lt;img src="http://jasonfollas.com/blog/aggbug/58.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jason Follas</dc:creator>
            <guid>http://jasonfollas.com/blog/archive/2008/12/11/using-ado.net-with-sql-server-spatial-objects.aspx</guid>
            <pubDate>Thu, 11 Dec 2008 19:04:12 GMT</pubDate>
            <comments>http://jasonfollas.com/blog/archive/2008/12/11/using-ado.net-with-sql-server-spatial-objects.aspx#feedback</comments>
            <wfw:commentRss>http://jasonfollas.com/blog/comments/commentRss/58.aspx</wfw:commentRss>
            <trackback:ping>http://jasonfollas.com/blog/services/trackbacks/58.aspx</trackback:ping>
        </item>
        <item>
            <title>SqlGeography: Ring Orientation of Polygon Interior Rings (Holes)</title>
            <link>http://jasonfollas.com/blog/archive/2008/11/25/sqlgeography-ring-orientation-of-polygon-interior-rings-holes.aspx</link>
            <description>&lt;p&gt;I have mentioned before how the Ring Orientation for the exterior ring of a Polygon is significant when instantiating a SqlGeography object.  In this case, a Counter-Clockwise orientation is required so that as an observer walks along the path, the interior of the Polygon is always to their left.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Ring Orientation for SqlGeography" hspace="5" align="right" src="http://jasonfollas.com/blog/images/jasonfollas_com/blog/9/r_RingOrientation.PNG" /&gt;But, what I have never really seen documented (or paid attention to, at least) is the fact that the interior rings, or holes, of a Polygon also have specific Ring Orientation requirements.  &lt;/p&gt;
&lt;p&gt;In keeping with the "Left-handed" rule, interior rings must be defined in a Clockwise manner - the opposite orientation of the shape's exterior ring.  This is because holes within a Polygon are considered to be part of the exterior of the shape, so the observer walking in a Clockwise direction is still keeping the Polygon's interior to their left.&lt;/p&gt;
&lt;p&gt;(I should note here that the Ring Orientation for SqlGeography is the exact opposite of ESRI's ShapeFile format, which is why Ring Orientation has been on my mind for the past few days).&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;&lt;img src="http://jasonfollas.com/blog/aggbug/55.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jason Follas</dc:creator>
            <guid>http://jasonfollas.com/blog/archive/2008/11/25/sqlgeography-ring-orientation-of-polygon-interior-rings-holes.aspx</guid>
            <pubDate>Tue, 25 Nov 2008 14:14:18 GMT</pubDate>
            <comments>http://jasonfollas.com/blog/archive/2008/11/25/sqlgeography-ring-orientation-of-polygon-interior-rings-holes.aspx#feedback</comments>
            <slash:comments>3</slash:comments>
            <wfw:commentRss>http://jasonfollas.com/blog/comments/commentRss/55.aspx</wfw:commentRss>
            <trackback:ping>http://jasonfollas.com/blog/services/trackbacks/55.aspx</trackback:ping>
        </item>
        <item>
            <title>Spatial: Determining Ring Orientation</title>
            <link>http://jasonfollas.com/blog/archive/2008/11/24/spatial-determining-ring-orientation.aspx</link>
            <description>&lt;p&gt;A Ring is a list of points such that the starting point and ending point are the same (forming a closed shape).  The order the you define the points that make up a Ring  - known as Ring Orientation - is significant, for various data formats (including SQL Server's Geography type) imply special meaning for rings that are defined in a clockwise manner as opposed to a counter-clockwise manner.  &lt;/p&gt;
&lt;p&gt;Given a list of points with no additional context, it can be difficult to determine the Ring Orientation being used.  &lt;/p&gt;
&lt;p&gt;For example, suppose that you have a generic list of points that represent the boundary of a postal code, and that you wish to use these points in order to construct a Polygon instance using the SqlGeography type.  SqlGeography happens to use "Left-handed" ordering, so that as an observer walks along the set of points in the order defined, the "inside" of the polygon is always to their left.  This also implies that the exterior ring of a Polygon is defined in a counter-clockwise manner.&lt;/p&gt;
&lt;p&gt;If you try to define a polygon with an area greater than a single hemisphere (this is a nice way to say "if you screw up and use the wrong orientation"), then the SqlGeography type will throw an exception.  So, aside from using Try-Catch, what can you do?&lt;/p&gt;
&lt;p&gt;While researching solutions to this problem, I stumbled upon a paper entitled "&lt;a href="http://www.engr.colostate.edu/~dga/dga/papers/point_in_polygon.pdf"&gt;A Winding Number and Point-in-Polygon Algorithm&lt;/a&gt;" from the Colorado State University.  It turns out that a simple algorithm with O(n) complexity can be used to determine if a point is within a Polygon, and a side effect also provides the Ring Orientation.  The key to this algorithm is determining the trend of the ring at each crossing of an axis.&lt;/p&gt;
&lt;p&gt;Since I was only interested in Ring Orientation (and not point enclosure detection), I didn't need to use this particular algorithm.  Instead, I took inspiration from the winding concept, and created a simpler derivative algorithm:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Visual example of how to determine ring orientation at the extreme left point" hspace="5" align="right" src="http://jasonfollas.com/blog/images/jasonfollas_com/blog/9/o_orientation_example.png" /&gt; &lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;Iterate the point collection and determine the extreme "left" and "right" points &lt;/li&gt;
    &lt;li&gt;Normalize the line segments connected to these points so that they each have the same "X" dimension length &lt;/li&gt;
    &lt;li&gt;Compare the "Y" values of the normalized segments to establish the trend through that extreme point (i.e., is the "previous" segment above or below the "next" segment) &lt;/li&gt;
    &lt;li&gt;In the spirit of the Winding algorithm, use opposite orientations for the left and right points so that the results coincide with one another &lt;/li&gt;
    &lt;li&gt;A negative result (negative indicates Clockwise orientation, positive result indicates Counter-Clockwise orientation, and a result of zero would be undefined &lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I've actually written (and posted) several versions of this algorithm, each time discovering some edge case exception that would cause me to take down the post and rewrite the algorithm.  I believe the code below works for all simple polygons on a Cartesian coordinate system (read: I have more testing to see if this will work with an ellipsoidal model, like SqlGeography).  &lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: The following code is generic in nature, and as such, I've defined my own Point structure instead of using a SqlGeometry or SqlGeography, etc. &lt;/em&gt;&lt;/p&gt;
&lt;pre class="c#" name="code"&gt;struct Point
{
    public double X { get; set; }
    public double Y { get; set; }
}

enum RingOrientation : int
{
    Unknown = 0,
    Clockwise = -1,
    CounterClockwise = 1
};

RingOrientation Orientation(Point[] points)
{
    // Inspired by http://www.engr.colostate.edu/~dga/dga/papers/point_in_polygon.pdf

    // This algorithm is to simply determine the Ring Orientation, so to do so, find the
    // extreme left and right points, and then check orientation

    if (points.Length &amp;lt; 4)
    {
        throw new ArgumentException("A polygon requires at least 4 points.");
    }

    if (points[0].X != points[points.Length - 1].X || points[0].Y != points[points.Length - 1].Y)
    {
        throw new ArgumentException("The array of points is not a polygon.  The first and last point must be identical.");
    }

    int rightmostIndex = 0;
    int leftmostIndex = 0;

    for (int i = 1; i &amp;lt; points.Length; i++)
    {
        if (points[i].X &amp;lt; points[leftmostIndex].X)
        {
            leftmostIndex = i;
        }
        if (points[i].X &amp;gt; points[rightmostIndex].X)
        {
            rightmostIndex = i;
        }
    }


    Point p0; // Point before the extreme
    Point p1; // The extreme point
    Point p2; // Point after the extreme

    double m; // Holds line slope

    double lenP2x;  // Length of the P1-P2 line segment's delta X
    double newP0y;  // The Y value of the P1-P0 line segment adjusted for X=lenP2x

    RingOrientation left_orientation;
    RingOrientation right_orientation;

    // Determine the orientation at the Left Point
    if (leftmostIndex == 0)
        p0 = points[points.Length - 2];
    else
        p0 = points[leftmostIndex - 1];

    p1 = points[leftmostIndex];

    if (leftmostIndex == points.Length - 1)
        p2 = points[1];
    else
        p2 = points[leftmostIndex + 1];

    m = (p1.Y - p0.Y) / (p1.X - p0.X);

    if (double.IsInfinity(m))
    {
        // This is a vertical line segment, so just calculate the dY to
        // determine orientation

        left_orientation = (RingOrientation)Math.Sign(p0.Y - p1.Y);
    }
    else
    {
        lenP2x = p2.X - p1.X;
        newP0y = p1.Y + (m * lenP2x);

        left_orientation = (RingOrientation)Math.Sign(newP0y - p2.Y);
    }



    // Determine the orientation at the Right Point
    if (rightmostIndex == 0)
        p0 = points[points.Length - 2];
    else
        p0 = points[rightmostIndex - 1];

    p1 = points[rightmostIndex];

    if (rightmostIndex == points.Length - 1)
        p2 = points[1];
    else
        p2 = points[rightmostIndex + 1];

    m = (p1.Y - p0.Y) / (p1.X - p0.X);

    if (double.IsInfinity(m))
    {
        // This is a vertical line segment, so just calculate the dY to
        // determine orientation

        right_orientation = (RingOrientation)Math.Sign(p1.Y - p0.Y);
    }
    else
    {
        lenP2x = p2.X - p1.X;
        newP0y = p1.Y + (m * lenP2x);

        right_orientation = (RingOrientation)Math.Sign(p2.Y - newP0y);
    }


    if (left_orientation == RingOrientation.Unknown)
    {
        return right_orientation;
    }
    else
    {
        return left_orientation;
    }
}


void Test()
{
    // Simple triangle - left extreme point is vertically "in between" line segments
    Point[] points = new Point[]
    {
        new Point(5,-1),
        new Point(0,0),
        new Point(5,1),
        new Point(5,-1)
    };

    System.Diagnostics.Debug.Assert(Orientation(points) == RingOrientation.Clockwise);
    Array.Reverse(points);
    System.Diagnostics.Debug.Assert(Orientation(points) == RingOrientation.CounterClockwise);

    // Case where both line segments are above the left extreme point
    points = new Point[]
    {
        new Point(2,1),
        new Point(0,0),
        new Point(1,1),
        new Point(2,1)
    };

    System.Diagnostics.Debug.Assert(Orientation(points) == RingOrientation.Clockwise);
    Array.Reverse(points);
    System.Diagnostics.Debug.Assert(Orientation(points) == RingOrientation.CounterClockwise);

    // Case where both line segments are below the left extreme point
    points = new Point[]
    {
        new Point(2,-1),
        new Point(0,0),
        new Point(1,-1),
        new Point(2,-1)
    };

    System.Diagnostics.Debug.Assert(Orientation(points) == RingOrientation.CounterClockwise);
    Array.Reverse(points);
    System.Diagnostics.Debug.Assert(Orientation(points) == RingOrientation.Clockwise);

    // Case where line segment is vertical (slope cannot be determined)
    points = new Point[]
    {
        new Point(0,0),
        new Point(0,1),
        new Point(1,1),
        new Point(1,0),
        new Point(0,0)
    };

    System.Diagnostics.Debug.Assert(Orientation(points) == RingOrientation.Clockwise);
    Array.Reverse(points);
    System.Diagnostics.Debug.Assert(Orientation(points) == RingOrientation.CounterClockwise);

    // Case where angle thru left extreme point is a right angle
    points = new Point[]
    {
        new Point(0,0),
        new Point(1,1),
        new Point(1,-1),
        new Point(0,0)
    };

    System.Diagnostics.Debug.Assert(Orientation(points) == RingOrientation.Clockwise);
    Array.Reverse(points);
    System.Diagnostics.Debug.Assert(Orientation(points) == RingOrientation.CounterClockwise);

    // Real-world case from a SHP file
    points = new Point[]
    {
        new Point(-156.92467299999998,20.738695999999997),
        new Point(-156.924636,20.738822),
        new Point(-156.924608,20.73894),
        new Point(-156.92458,20.739082),
        new Point(-156.92460599999998,20.739234),
        new Point(-156.924551,20.739326),
        new Point(-156.924507,20.739241999999997),
        new Point(-156.924482,20.739082),
        new Point(-156.924466,20.738854999999997),
        new Point(-156.924387,20.738602999999998),
        new Point(-156.924308,20.738325),
        new Point(-156.924239,20.738063999999998),
        new Point(-156.92424,20.737887999999998),
        new Point(-156.924285,20.737811999999998),
        new Point(-156.924475,20.73762),
        new Point(-156.92458299999998,20.737603999999997),
        new Point(-156.924754,20.737579),
        new Point(-156.924851,20.737731),
        new Point(-156.924956,20.738101),
        new Point(-156.924909,20.738343999999998),
        new Point(-156.924818,20.738487),
        new Point(-156.92467299999998,20.738695999999997)
    };

    System.Diagnostics.Debug.Assert(Orientation(points) == RingOrientation.Clockwise);
    Array.Reverse(points);
    System.Diagnostics.Debug.Assert(Orientation(points) == RingOrientation.CounterClockwise);

}&lt;/pre&gt;&lt;img src="http://jasonfollas.com/blog/aggbug/54.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jason Follas</dc:creator>
            <guid>http://jasonfollas.com/blog/archive/2008/11/24/spatial-determining-ring-orientation.aspx</guid>
            <pubDate>Mon, 24 Nov 2008 18:00:46 GMT</pubDate>
            <comments>http://jasonfollas.com/blog/archive/2008/11/24/spatial-determining-ring-orientation.aspx#feedback</comments>
            <wfw:commentRss>http://jasonfollas.com/blog/comments/commentRss/54.aspx</wfw:commentRss>
            <trackback:ping>http://jasonfollas.com/blog/services/trackbacks/54.aspx</trackback:ping>
        </item>
        <item>
            <title>Upcoming Events</title>
            <link>http://jasonfollas.com/blog/archive/2008/09/25/upcoming-events.aspx</link>
            <description>&lt;p&gt;There are a few events taking place in October that I would like to promote:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a target="_blank" href="http://www.dodn.org"&gt;&lt;font size="4"&gt;Day of .NET in Ann Arbor&lt;/font&gt;&lt;/a&gt;&lt;font size="4"&gt;&lt;br /&gt;
Saturday, October 18, 2008&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img hspace="5" align="left" alt="" src="http://www.dodn.org/AnnArbor/Fall2008/images/AnnArbor2008HBadge.png" /&gt;The fourth Day of .NET in Ann Arbor event will take place on the campus of Washenaw Community College in Ann Arbor (or is it actually Ypsilanti?  I can never tell).  The original conference was a collaboration between &lt;a target="_blank" href="http://www.migang.org"&gt;GANG&lt;/a&gt;, &lt;a target="_blank" href="http://www.aadnd.org"&gt;AADND&lt;/a&gt;, and &lt;a target="_blank" href="http://www.nwnug.com"&gt;NWNUG&lt;/a&gt;.  This year, we have officially added &lt;a target="_blank" href="http://portal.artemis-solutions.com/glugnet/"&gt;GLUG.net&lt;/a&gt; and &lt;a target="_blank" href="http://www.grdotnet.org/"&gt;West Michigan&lt;/a&gt; to the list of groups who are assisting in the organization and promotion.  So, for those of you following along at home, this event is the product of &lt;u&gt;FIVE&lt;/u&gt; regional user groups, and like its predecessors, should be a great day of learning and networking.&lt;/p&gt;
&lt;p&gt;The session list has been posted, and there should be something on the schedule for everyone.  Registration is free, and all that we ask is that if you do sign up, then &lt;u&gt;please show up&lt;/u&gt;.  There's nothing worse than wasting sponsorship dollars by ordering too much food or too many T-Shirts (though, this year, we're going to try to get Pizza back on the menu, so food waste should hopefully be minimized).&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;&lt;a target="_blank" href="http://www.dayofdotnet.org/AnnArbor/Fall2008/Sessions.aspx"&gt;http://www.dayofdotnet.org/AnnArbor/Fall2008/Sessions.aspx&lt;/a&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;&lt;font size="4"&gt;&lt;a target="_blank" href="http://www.nwnug.com/PermaLink,guid,20233af5-bc9f-4bf3-a1b4-5fa94233328b.aspx"&gt;Wally McClure appearing at Northwest Ohio .NET User Group&lt;/a&gt;&lt;br /&gt;
Monday, October 20, 2008&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;img hspace="5" align="left" alt="" src="http://upload.wikimedia.org/wikipedia/en/thumb/6/6c/Troymcclure.png/120px-Troymcclure.png" /&gt;"Hello.  I'm Wally McClure.  You might remember me from my many books published by Wrox Press with my picture on them.  Or, the &lt;a target="_blank" href="http://aspnetpodcast.com/CS11/"&gt;ASP.NET Podcast&lt;/a&gt;, where on the website, you'll find pictures of my books with my pictures on them. Or, the very popular &lt;a target="_blank" href="http://geekswithblogs.net/images/geekswithblogs_net/rowser/WindowsLiveWriter/IhavemoreWallyinmylife_148F8/PIC_0185_thumb.jpg"&gt;T-Shirt with my picture on the back&lt;/a&gt;...."&lt;/p&gt;
&lt;p&gt;I met &lt;a href="http://morewally.com"&gt;Wally&lt;/a&gt; this summer at TechEd Developer in Orlando, where one of the first experiences was being crammed into the back seat of a car between him and &lt;a target="_blank" href="http://www.keithelder.net"&gt;Keith Elder&lt;/a&gt;.  He seemed to take a liking to me, and let's just say that my phone now receives more random text messages than ever before.  :-)  &lt;/p&gt;
&lt;p&gt;In all seriousness, Wally was supposed to have appeared at NWNUG in June, just after TechEd, but had to back out due to work commitments (&lt;a target="_blank" href="http://stevesmithblog.com/"&gt;Steve Smith&lt;/a&gt; ended up filling in for him).  We're thrilled that he was still interested in coming to Toledo, and we were able to arrange an October 20th date (note that this is a Monday, not the regular Tuesday meeting night).&lt;/p&gt;
&lt;p&gt;Watch the NWNUG website for further details about the meeting topic.&lt;/p&gt;&lt;img src="http://jasonfollas.com/blog/aggbug/53.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jason Follas</dc:creator>
            <guid>http://jasonfollas.com/blog/archive/2008/09/25/upcoming-events.aspx</guid>
            <pubDate>Thu, 25 Sep 2008 16:50:25 GMT</pubDate>
            <comments>http://jasonfollas.com/blog/archive/2008/09/25/upcoming-events.aspx#feedback</comments>
            <wfw:commentRss>http://jasonfollas.com/blog/comments/commentRss/53.aspx</wfw:commentRss>
            <trackback:ping>http://jasonfollas.com/blog/services/trackbacks/53.aspx</trackback:ping>
        </item>
        <item>
            <title>Help!</title>
            <link>http://jasonfollas.com/blog/archive/2008/09/15/help.aspx</link>
            <description>&lt;p&gt;&lt;font face="Arial"&gt;Dear Microsoft,&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;We've been pals for a long time, right?  You put out all of these great technologies, and I help others to use them within their own organization.  We have a good thing going, you and me.&lt;/p&gt;
&lt;p&gt;But, I have a problem.  You see, whenever I press this one special key on my keyboard, mostly by accident due to its proximity to ESC and ~, you give me an excuse to stop working and go get coffee.  This isn't very productive.  I don't always want an excuse to get coffee.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://jasonfollas.com/blog/images/jasonfollas_com/blog/9/r_helpdialog.png" /&gt;&lt;/p&gt;
&lt;p&gt;Can you please add a Cancel button or something?  Your modal dialog is not very friendly at times.&lt;/p&gt;
&lt;p&gt;BFF,&lt;/p&gt;
&lt;p&gt;-Jason&lt;/p&gt;&lt;img src="http://jasonfollas.com/blog/aggbug/51.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jason Follas</dc:creator>
            <guid>http://jasonfollas.com/blog/archive/2008/09/15/help.aspx</guid>
            <pubDate>Mon, 15 Sep 2008 18:24:12 GMT</pubDate>
            <comments>http://jasonfollas.com/blog/archive/2008/09/15/help.aspx#feedback</comments>
            <slash:comments>3</slash:comments>
            <wfw:commentRss>http://jasonfollas.com/blog/comments/commentRss/51.aspx</wfw:commentRss>
            <trackback:ping>http://jasonfollas.com/blog/services/trackbacks/51.aspx</trackback:ping>
        </item>
        <item>
            <title>Announcing Tourniquet</title>
            <link>http://jasonfollas.com/blog/archive/2008/08/18/announcing-tourniquet.aspx</link>
            <description>&lt;p&gt;Have you ever gotten an idea stuck in your head?  One that you start your day thinking about in the shower, and then try as you might, you just can't get rid of it?&lt;/p&gt;
&lt;p&gt;That's what happened to me a few months ago.  Specifically, I started thinking about &lt;a href="http://twitter.com/jfollas"&gt;Twitter&lt;/a&gt;, and the problems that it was experiencing.  At that time, the "Fail Whale" was making very frequent appearances, indicating that Twitter was having problems keeping up with the demands being made on it.  My Tweeps (social networking friends on Twitter), all with short attention spans like myself, began chattering about moving to a more reliable platform.  &lt;/p&gt;
&lt;p&gt;But, in my estimation, Twitter was still the best platform to remain on.  Among other things, it was actually the most "mature" in its class - if you can call something a mere two years old as being mature.&lt;/p&gt;
&lt;h4&gt;So, Jason, what is Tourniquet?&lt;/h4&gt;
&lt;p&gt;&lt;font face="Arial"&gt;After quite a few weeks of thinking about the various problems that I was aware of, I came up with a pretty simple solution.  I needed to bounce some ideas off of a sounding board, so I fired off an email to some of my friends: &lt;a target="_blank" href="http://netcave.org/"&gt;Alan Stevens&lt;/a&gt;, &lt;a target="_blank" href="http://keithelder.net"&gt;Keith Elder&lt;/a&gt;, and &lt;a target="_blank" href="http://www.michaeleatonconsulting.com/"&gt;Micheal Eaton&lt;/a&gt;.  &lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;The contents of that email still serve as a pretty good overview for my vision, which has been realized as "Tourniquet":&lt;/font&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Think of a multi-faceted approach to fixing Twitter's issues that ultimately concentrates on reducing the number of calls that you make into Twitter itself, as well as provides transparent access to Twitter data during Twitter downtimes:&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;1. A personal Twitter proxy.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;This is simply an API passthrough service that you host yourself.  The thought process here is that Witty and other clients could be configured as to what server is accessed to execute an API call (i.e., by default, it's &lt;font face="Courier New"&gt;http://www.twitter.com/&lt;/font&gt;, but someone hosting a Twitter proxy would be able to specify something like &lt;font face="Courier New"&gt;http://thisismydomainyo.com/tourniquet/&lt;/font&gt; ).  Aside from the server, there's nothing different about the request or response.  That is, the client might hit &lt;font face="Courier New"&gt;http://thisismydomainyo.com/tourniquet/statuses/friends_timeline.xml &lt;/font&gt;instead of&lt;br /&gt;
&lt;font face="Courier New"&gt;http://www.twitter.com/statuses/friends_timeline.xml&lt;/font&gt;.  &lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;This is not a public/shared service - it would be intended for just the user.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;2. Obfuscation/encryption&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Network Nazis suck, and so do people who brag about having smart phones and data plans.  :-)  There may be other reasons why someone would want the URL obfuscated and the response from Twitter encrypted when transfered between the Twitter Proxy and the client.  But, that's what I'm talking about.  Clients would need to be modified to support encryption/obfuscation before the user can utilize it.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;3. Caching&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;While the Tourniquet proxy is fetching the information from Twitter, it might as well cache it to some form of persistent storage.  This can be used to save some calls into the Twitter API, especially for historical data (which is also useful for when they disable access to historical data during times of heavy demand)&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt; &lt;font face="Arial"&gt;4. Store and Forward&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Is Twitter down?  Damn!  But, no worries with Tourniquet!  Your status update is saved until Twitter comes back up.  This is really no different than other store-and-forward services, except you're not giving your twitter credentials to some unknown third party website.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt; &lt;font face="Arial"&gt;5. Automated fetching&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Perhaps Tourniquet can periodically fetch your timeline for you and cache it, either by means of some external triggering or by a timer. Then, when you hit the proxy to check for updates, it's already there (and your current request would likely trigger another fetch just to make sure that it has the latest data)&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt; &lt;font face="Arial"&gt;6. Tribe-Net Sharing/Synchronization&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Here's where the service gets interesting: @keithelder and @jfollas follow each other, and both run Tourniquet.  So, both proxies can be configured to be able to sync statuses between each other, hopefully saving some Twitter API hits that count towards your hourly usage. (I'm thinking that Direct Messages can somehow be used to announce Tourniquet endpoints).  If Twitter is down and there are some status updates that are available (but not yet on Twitter), those can be propogated across the cloud via proxy-to-proxy synchronization. Eventually, they'll show up as actual Twitter statuses.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;I picture the communication resembling something like this:&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;@jfollas's proxy calls @keithelder's proxy, and announces the highest message ID for each person that @jfollas follows.  @keithelder's proxy returns a list statuses for each of those people that it has cached where the message ID is higher (plus any new/unpublished statuses that are in store-and-forward).  @keithelder's proxy will need to call @jfollas's proxy to reciprocate the process.&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Arial"&gt;Another possibility is to also synchronize a single person, perhaps with the goal of maintaining a cache of the last 100 tweets per person on your follow list.  In this case, @jfollas's proxy will call @keithelder's proxy and list all of the message id's that it has cached for the person.  If @keithelder is also following that person (or otherwise happens to have some tweets cached for the person), then any new messages (or any in-between messages that @jfollas's proxy might have missed) will be supplied in the response.&lt;/font&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That was the original concept.  The name "Tourniquet" came from the same place where all good project names come from: the Thesaurus.  I simply looked for synonyms for the word "bandage", stumbled upon this word, and discovered that it was not already well-known as a software product.&lt;/p&gt;
&lt;h4&gt;Alright, sounds good.  Where is Tourniquet?&lt;/h4&gt;
&lt;p&gt;Tourniquet is not a product, per se.  It's a project, and an open source project at that (MIT license).  You can download the source and do just about anything with it from the project site on Codeplex:&lt;/p&gt;
&lt;p align="center"&gt;&lt;a href="http://codeplex.com/tourniquet"&gt;&lt;img alt="Tourniquet Logo" border="0" src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=tourniquet&amp;amp;DownloadId=41394" /&gt;&lt;br /&gt;
http://codeplex.com/tourniquet&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To run Tourniquet, you will need to grab the release from Codeplex, set up a database (i.e., run the create scripts), copy the files from the release to your webserver, and then set up a new web application on your webserver.  If this sounds too complicated, then perhaps you should wait until it's a little more refined before checking it out.  I'm just sayin'...   :-P&lt;/p&gt;
&lt;p&gt;As I wrote the code, I tried to keep in mind that not everyone has a really sweet hosting deal.  Therefore, I targeted what I thought to be the lowest common denominators: ASP.NET 2.0 and SQL Server 2005.  &lt;/p&gt;
&lt;p&gt;Classifying SQL Server as a LCD, though, bothered me, for a lot of "common man" hosting plans do not include access to a database at all.  But, being a SQL Server MVP, I found this to be the quickest way to build the prototype and release the project to Codeplex.  The persistance layer actually uses the Provider model, so my goal is to make alternative providers that do not require SQL Server (i.e., maybe XML on the filesystem, or Amazon SimpleDB, etc).&lt;/p&gt;
&lt;p&gt;The point that I'd like to drive home is that the current codebase is very much a proof-of-concept or prototype, albeit a fully functional one (I've been using it for a few weeks).  People may point at my code and say "Why did you do this like that?  Where are your tests?  This code sucks!" and that's okay.  In its current form, it does most of what I outlined in the email above, so I'm content (working software is the #1 measure of success).&lt;/p&gt;
&lt;p&gt;I encourage anyone who wants to participate in taking this prototype to the next level to join the development team.  Contact me through the site, Codeplex, or Twitter (@jfollas).  I'd be very happy if some enthusiastic people could take on the development of parts of the system and run with it.&lt;/p&gt;&lt;img src="http://jasonfollas.com/blog/aggbug/49.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jason Follas</dc:creator>
            <guid>http://jasonfollas.com/blog/archive/2008/08/18/announcing-tourniquet.aspx</guid>
            <pubDate>Mon, 18 Aug 2008 04:16:43 GMT</pubDate>
            <comments>http://jasonfollas.com/blog/archive/2008/08/18/announcing-tourniquet.aspx#feedback</comments>
            <wfw:commentRss>http://jasonfollas.com/blog/comments/commentRss/49.aspx</wfw:commentRss>
            <trackback:ping>http://jasonfollas.com/blog/services/trackbacks/49.aspx</trackback:ping>
        </item>
    </channel>
</rss>