<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	>

<channel>
	<title>Software Development Blog</title>
	<atom:link href="http://dev.forrestcroce.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://dev.forrestcroce.com</link>
	<description>Innovative Concepts and Open Source Goodies</description>
	<pubDate>Wed, 09 Jun 2010 21:09:30 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.7</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Exif Harvester 1.2 Supports GeoTagging</title>
		<link>http://dev.forrestcroce.com/exif-harvester-1-2-supports-geotagging/2010-06-09/</link>
		<comments>http://dev.forrestcroce.com/exif-harvester-1-2-supports-geotagging/2010-06-09/#comments</comments>
		<pubDate>Wed, 09 Jun 2010 21:09:30 +0000</pubDate>
		<dc:creator></dc:creator>
		
		<category><![CDATA[C#]]></category>

		<category><![CDATA[GIS]]></category>

		<category><![CDATA[geography]]></category>

		<category><![CDATA[gpx]]></category>

		<category><![CDATA[photography]]></category>

		<guid isPermaLink="false">http://dev.forrestcroce.com/?p=135</guid>
		<description><![CDATA[Exif Harvester is software I&#8217;ve been working on since 2006;  the project grew out of my own need to analyze metadata from my photos.  For example, lenses are expensive, and should be sold if they&#8217;re not getting enough use.  Geotagging has been something of a holy grail since the project started, as [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://forrestcroce.com/Software/ExifHarvester.html">Exif Harvester</a> is software I&#8217;ve been working on since 2006;  the project grew out of my own need to analyze metadata from my photos.  For example, lenses are expensive, and should be sold if they&#8217;re not getting enough use.  Geotagging has been something of a holy grail since the project started, <a href="http://blog.forrestcroce.com/granite-mountain-lookout/2009/12/29/satellite-map-granite-mountain/" target="_blank">as you might guess from maps like these</a>.</p>
<p>Geo-tagging means associating something - in this case, photos - with its relevant geography - in this case, where the photos were created.  This is done by matching the date and time an exposure was made against GPS data.  Of course <a href="http://www.google.com/#hl=en&amp;source=hp&amp;q=geotag+photos" target="_blank">there are many ways to skin a cat</a>, but Exif Harvester does some of its work in downright unique ways.</p>
<h2>Better Geo Data</h2>
<p>Some of what Exif Harvester does to improve the quality of its data are:</p>
<p><strong>Camera offset</strong> - GPS units always have exactly the correct time;  this is <a href="http://en.wikipedia.org/wiki/Global_Positioning_System" target="_blank">how GPS works</a>.  Your camera may not have the right time, however.  Mine is certainly off, and after I set it, it eventually drifts a bit.  A large time difference would yield a large geographic error, if time stamps were simply matched up.  Instead, when you download and tag your photos, you can tell Exif Harvest how far your camera&#8217;s clock is from the GPS clock, and this offset will be honored when your photos are geo-tagged.</p>
<p><strong>Point averaging</strong> - A common pitfall to geo-tagging software is that most programs simply find the nearest point, and assign it to your photos.  Exif Harvester is a bit more subtle:  if no point in your GPS data exactly matches the time stamp from an image ( adjusted for the camera offset ), the closest points before and after the photo was created, and calculate a <em><strong>weighted</strong> average</em> from them.  For example, it might take half an hour to fly from Seattle to Vancouver;  if you shoot a photo ten minutes into the trip, it will be geo-coded to appear 1/3 of the way between these cities, rather than in either of them or halfway between.</p>
<h2>Some Guesswork, Too</h2>
<p>While the latitude, longitude, and elevation values are discovered in a very robust way, Exif Harvester will attempt to guess which direction the camera may have been facing when an exposure was made.  This is done by calculating the <a href="http://en.wikipedia.org/wiki/Bearing_%28navigation%29" target="_blank">bearing</a> between an image&#8217;s nearest points.</p>
<p>Obviously, this is not of the same quality as the geographic coordinates.  It&#8217;s just not a safe assumption that people always take photographs with the camera pointed in the direction they&#8217;ve been walking.  Still, this will be right some ( maybe even a lot ) of the time, and a guess is often better than no information whatsoever.  So use or ignore this at your own discretion.</p>
<h2>Simplified Workflow</h2>
<p>Exif Harvester is not limited to geo-tagging a batch of photos from a single GPS file.  If you don&#8217;t correlate your GPS files, you can simply point to all of your GPS data.  Any files with no useful data will simply not return any search hits.  You can of course point to a single file, a list of files, or to a folder full of GPS files, which will then be loaded recursively for the harvest.</p>
<p>Like other metadata, the geography information can be written out to XML, CSV, or other types of files.  This data is much easier to work with in Excel, SQL, or whatever tool you may prefer.</p>
<h2>Misc</h2>
<p>Other improvements in this release include:</p>
<ul>
<li>Sortable columns in the image file list</li>
<li>Image previews</li>
<li>A somewhat cleaner user interface</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://dev.forrestcroce.com/exif-harvester-1-2-supports-geotagging/2010-06-09/feed/</wfw:commentRss>
		</item>
		<item>
		<title>A Geographic Distance Class in C#</title>
		<link>http://dev.forrestcroce.com/a-geographic-distance-class-in-c/2010-01-16/</link>
		<comments>http://dev.forrestcroce.com/a-geographic-distance-class-in-c/2010-01-16/#comments</comments>
		<pubDate>Sat, 16 Jan 2010 00:17:05 +0000</pubDate>
		<dc:creator></dc:creator>
		
		<category><![CDATA[C#]]></category>

		<category><![CDATA[GIS]]></category>

		<category><![CDATA[geography]]></category>

		<category><![CDATA[gpx]]></category>

		<guid isPermaLink="false">http://dev.forrestcroce.com/?p=103</guid>
		<description><![CDATA[The .NET Framework is pretty feature rich, helping developers put applications together quickly.  A glaring omission, however, is support for anything to do with geography.  I recently had a need to deal with distances between points in GPS files, calculated using the haversine formula, and came up with an elegant solution.
I modeled my [...]]]></description>
			<content:encoded><![CDATA[<p>The .NET Framework is pretty feature rich, helping developers put applications together quickly.  A glaring omission, however, is support for anything to do with geography.  I recently had a need to deal with distances between points in GPS files, calculated using the <a title="Wikipedia article explaining the math" href="http://en.wikipedia.org/wiki/Haversine_formula" target="_blank" rel="nofollow">haversine formula</a>, and came up with an elegant solution.</p>
<p>I modeled my class, Distance, on the TimeSpan struct, with a few important changes.  This should make the programming model as familiar as possible.  Just as a TimeSpan converts the same value ( <em>say, 36 hours</em> ) between different formats ( <em>1.5 days;  2,160 minutes, etc</em> ), a Distance object converts between formats like feet, meters, and miles.</p>
<p>If this isn&#8217;t clear, a short code sample should help.  The full code can be found at <a href="http://dev.forrestcroce.com/source-code/GPX/Distance.cs.html">Distance.cs</a>.</p>
<p><code></p>
<pre class="prettyprint" lang="C#">
Distance d = new Distance();

d.Miles = 1;
Debug.Assert(d.Yards == 1760);
Debug.Assert(d.Feet == 5280);
Debug.Assert(d.Inches == 63360);
</pre>
<p></code></p>
<p><span id="more-103"></span>Because I&#8217;ve used the TimeSpan structure as a model, in explaining the Distance class as much as in developing it, there are a few important differences I should point out.</p>
<h2>Enums (UnitSystem, ImperialUnits, MetricUnits)</h2>
<p>A raw number has no meaning when divorced from its context;  three <em>what</em>?  While the elevation data in a GPS tracklog comes in meters, many US residents would prefer to see this in feet.  There are three structures that provide the context that makes this data meaningful.  These should be fairly self explanatory ( ImperialUnits contains inches, feet, etc while MetricUnits contains centimeters,  kilometers, and more ), but it&#8217;s worth mentioning that a third struct, UnitSystem, distinguishes between the two.  I felt this was a better model than simply listing every available type of 2D measurement in one enumeration ( feet, meters, and furlongs - oh my! ).</p>
<p>This leads to a curious paradigm for calling code - what you&#8217;ll write if you use this class.  Several methods have three specific overloads, taking a decimal value and one of the following types:  ImperialUnits, MetricUnits, or Enum.  The third overload, taking a base Enum, lets you abstract away the specific type.  The code sample below shows three ways to instantiate a Distance object with a value.</p>
<p><code></p>
<pre class="prettyprint" lang="C#">
Distance d1 = new Distance(1, ImperialUnits.Mile);
Distance d2 = new Distance(2, MetricUnits.Meter);

Enum unit = userText == "mile" ? ImperialUnits.Mile : MetricUnits.Meter;
Distance d3 = new Distance(2, unit);
</pre>
<p></code></p>
<h2>Normalize</h2>
<p>While the method name may give away my background as a SQL Server developer, it has a different, but equally important meaning here.  The flexibility of the Distance class would make comparisons a little bit cumbersome;  one instance could describe inches while the other might be in miles or meters.  Therefore, the ( static ) normalize method takes two Distance arguments, and returns the value ( as a System.Decimal ) of the second in terms of the first.  In other words, if you ask for 1 yard to be normalized against 1 foot, the result will be the value 3.</p>
<h2>Operator Overloads</h2>
<p>I&#8217;ve overloaded <span style="font-weight:bold; color: red">+</span> and <span style="font-weight:bold; color: red">-</span> as well as <span style="font-weight:bold; color: red">&lt;</span> and <span style="font-weight:bold; color: red">&gt;</span> in the Distance class, which cascade so that <span style="font-weight:bold; color: red">+=</span>, <span style="font-weight:bold; color: red">-=</span>,  <span style="font-weight:bold; color: red">&lt;=</span>, and <span style="font-weight:bold; color: red">&gt;=</span> are also redefined.</p>
<p>Part of the reason I chose to implement distance as a class and not a struct is to retain the object semantics most developers are used to, which includes identity comparisons by default, and the ability to change the value in an instance without creating a second instance ( eg values in a list ).  This means that <span style="font-weight:bold; color: red">==</span> is left to determine whether two <em>instances</em> are the same object in memory, not whether they have the same value.</p>
<h2>Direct Access to Internal Values</h2>
<p>Again, owing to the flexibility of representation, I felt it necessary ( although a bit dangerous ) to provide access to the underlying data.</p>
<p>You can set an object&#8217;s value by calling its specialized properties ( <code><em>d.Miles = 2;</em></code> ), however, if you have a variable representing the unit to use and would prefer to abstract the call, the SetValue method allows this ( <code><em>d.SetValue(2, ImperialUnits.Mile);</em></code> ).</p>
<p>A read-only property, InternalValue, gives developers a choice for how to perform value comparisons.  This is paired  with a second property, InternalUnit, of type Enum, and two others provided only for convenience, to avoid casting in client code:  InternalMetricUnit, and InternalImperialUnit, plus, finally, an InternalUnitType property telling you which to use.  While this may sound complicated, it is very easy to code against.  You can compare the same property ( Meters, for example ) from two objects to determine whether they have the same value, avoid the mess by calling Normalize as described above, or compare the internal values and types.</p>
<h2>System.Decimal</h2>
<p>The decimal struct is much slower than the double, but it allows much greater precision after the decimal point.  Because of the way IEEE defines floating point representations, there are many fractional values that cannot be represented exactly as a single or double precision float.  Decimals, apart from using more bytes for storage, use a base-ten representation of both parts of the number, although this is done in .net code, and is truly a software solution.  I feel that this is an acceptable trade-off, however;  I don&#8217;t expect a great deal of math to be done against Distance objects, but I do expect people will be startled if metric calculations don&#8217;t work as expected.</p>
<h2>Unit Tests</h2>
<p>This class has been heavily tested, with at least one non-trivial conversion from every unit to every other unit.  All code paths through Normalize have also been tested.</p>
<p>I&#8217;m not publishing the tests, however, as I don&#8217;t believe they have much or any use other than in preserving my sanity while I wrote this code.  If I&#8217;m wrong and you could benefit from the tests, leave a comment and I&#8217;ll be happy to provide them, but, for brevity&#8217;s sake, I&#8217;ll point you at <a href="http://dev.forrestcroce.com/source-code/GPX/Distance.cs.html">the actual code</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://dev.forrestcroce.com/a-geographic-distance-class-in-c/2010-01-16/feed/</wfw:commentRss>
		</item>
		<item>
		<title>dbo.QueryPlan (Function)</title>
		<link>http://dev.forrestcroce.com/dbo-query-plan-function/2009-08-19/</link>
		<comments>http://dev.forrestcroce.com/dbo-query-plan-function/2009-08-19/#comments</comments>
		<pubDate>Wed, 19 Aug 2009 18:25:08 +0000</pubDate>
		<dc:creator></dc:creator>
		
		<category><![CDATA[Performance]]></category>

		<category><![CDATA[SQL]]></category>

		<category><![CDATA[code]]></category>

		<category><![CDATA[debugging]]></category>

		<guid isPermaLink="false">http://dev.forrestcroce.com/?p=83</guid>
		<description><![CDATA[Our last post described how to see what another connection to a SQL Server is doing, with a user-defined function, dbo.InputBuffer.  Given a spid, the function returns the SQL text being run on that connection - or the last command received from the connection, depending on which version you decided to use.  Along [...]]]></description>
			<content:encoded><![CDATA[<p>Our last post described how to see what another connection to a SQL Server is doing, with <a href="http://dev.forrestcroce.com/dbo-inputbuffer-function/2009-08-17/">a user-defined function, dbo.InputBuffer</a>.  Given a spid, the function returns the SQL text being run on that connection - or the last command received from the connection, depending on which version you decided to use.  Along the same lines, it can often be more useful to find the query plan.</p>
<p>Because the execution plan generated by a SQL command changes for many reasons ( schema changes, data volume, etc ), knowing what a spid is doing might not be as important as knowing how the spid is doing it.  For example, an ETL might suddenly run for hours, as the result of a table scan &#8230; but why?  The function below can help a developer or DBA troubleshoot performance and concurrency issues.</p>
<p><code>
<pre class="prettyprint" lang="sql">
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
GO

If Exists (Select * From sys.objects Where object_id = object_id(N'dbo.QueryPlan') AND type in (N'FN', N'IF', N'TF', N'FS', N'FT'))
        Drop Function dbo.QueryPlan
GO

Create Function dbo.QueryPlan(@spid int) Returns xml As Begin
	Declare
		@plan_handle binary(32),
		@code xml

	Select @plan_handle = plan_handle
	From sys.dm_exec_requests
	Where session_id = @spid;

	Select @code = query_plan From sys.dm_exec_query_plan(@plan_handle);

	Return @code
End</pre>
<p></code></p>
<p><span id="more-83"></span>This of course deserves the same warning as the input buffer function;  the <i style="color: blue">sys.dm_exec_requests</i> view only tracks things that are running at the time you query it.  If you&#8217;d like this function to return the most recent query plan used by a connection, change the code to look up the plan handle from <i style="color: blue">sys.dm_exec_connections</i> instead.  Of course, there are good reasons for wanting a null return value for idle connections.</p>
<p>Because this is a scalar function, it can be used in a select list.  We can extend the sample query introduced yesterday, to call dbo.QueryPlan and dbo.InputBuffer for all transactions involved in a blocking chain.</p>
<p><code>
<pre class="prettyprint" lang="sql">
Select
	dbo.InputBuffer(spid) As RunningCode,
	dbo.QueryPlan(spid) As QueryPlan,
	*
From
	sys.sysProcesses
Where
	blocked != 0
	Or spid In (Select blocked From sys.sysProcesses)
</pre>
<p></code><br />
fnbki8pjqe</p>
]]></content:encoded>
			<wfw:commentRss>http://dev.forrestcroce.com/dbo-query-plan-function/2009-08-19/feed/</wfw:commentRss>
		</item>
		<item>
		<title>dbo.InputBuffer (Function)</title>
		<link>http://dev.forrestcroce.com/dbo-inputbuffer-function/2009-08-17/</link>
		<comments>http://dev.forrestcroce.com/dbo-inputbuffer-function/2009-08-17/#comments</comments>
		<pubDate>Mon, 17 Aug 2009 21:47:53 +0000</pubDate>
		<dc:creator></dc:creator>
		
		<category><![CDATA[SQL]]></category>

		<category><![CDATA[code]]></category>

		<category><![CDATA[Performance]]></category>

		<guid isPermaLink="false">http://dev.forrestcroce.com/?p=50</guid>
		<description><![CDATA[Background
Most people who use SQL Server regularly, know about the wonderful DBCC InputBuffer command.  If you&#8217;re not a SQL aficionado, you can easily find out what other connections &#8220;are doing&#8221; when one of them starts causing problems.  Checking the input buffer - how commands are received by the server - returns the SQL [...]]]></description>
			<content:encoded><![CDATA[<h2>Background</h2>
<p>Most people who use SQL Server regularly, know about the wonderful DBCC InputBuffer command.  If you&#8217;re not a SQL aficionado, you can easily find out what other connections &#8220;are doing&#8221; when one of them starts causing problems.  Checking the input buffer - how commands are received by the server - returns the SQL code that was most recently sent from that connection.<span id="more-50"></span></p>
<p>For example, if spid ( <b>S</b>erver <b>P</b>rocess <b>Id</b>entifier ) #72 is blocking other transactions, or chewing up an alarming amount of disc I/O ( especially if it&#8217;s an ad hoc query ), you can find out what it&#8217;s up to by calling:</p>
<p><code></p>
<pre class="prettyprint" lang="sql">
DBCC InputBuffer (72)
</pre>
<p></code></p>
<p>Which returns something like this:</p>
<table>
<tr style="font-weight:bold;">
<td>EventType</td>
<td>Parameters</td>
<td>EventInfo</td>
</tr>
<tr style="height: 1px; background-color: black;">
<td colSpan="3"></td>
</tr>
<tr style="vertical-align: top;">
<td>Language Event</td>
<td>0</td>
<td>declare @spid int  set @spid = 72      Declare   @plan_handle binary(32),   @code xml    Select @plan_handle = plan_handle  From sys.dm_exec_requests  Where session_id = @spid;    Select @code = query_plan From  sys.dm_exec_query_plan(@plan_handle)</td>
</tr>
</table>
<h2>Beyond the Basics</h2>
<p>This is a good start, but has some issues.  Most importantly, the results simply aren&#8217;t available to T-SQL code.  You can write an application to call DBCC externally - the Activity Monitor does this, giving you the SQL involved when you double click a process - but this limits the utility.  For example, if you run sp_who2 and find a dozen questionable spids, you will have to check them individually.</p>
<p>On the other hand, a user-defined function ( UDF ) opens many doors.  Logging comes immediately to mind, and will be the subject of a future post.  A more straight-forward use for a SQL function is to simply ask what&#8217;s running on the server:</p>
<p><code></p>
<pre class="prettyprint" lang="sql">
Select
	dbo.InputBuffer(spid) As RunningCode,
	*
From
	sys.sysProcesses
Where
	blocked != 0
	Or spid In (Select blocked From sys.sysProcesses)
</pre>
<p></code></p>
<p>Instead of simply getting a dump of the spid/kpid values involved, the CPU and I/O numbers, etc, this query returns <i>at-a-glance</i> what each connection is <i>doing</i>.  The where clause in the query above will return only connections that are involved in a blocking chain - which is useful when debugging concurrency issues - but the concept applies no matter what you&#8217;re doing.  You could rewrite the query &#8220;<i style="color: blue">&#8230; Where dbo.InputBuffer(spid) Like &#8216;<span style="color:red;">%My_Table_Name%</span>&#8216; &#8230;</i>&#8221; to see which transactions are trying to use a table, and what they&#8217;re doing with it.</p>
<h2>The Code</h2>
<p>The T-SQL batch below creates a function named <i><b>dbo.InputBuffer</b></i> to the database.  This could of course be deployed to any schema;  dbo is used for simplicy, as it exists by default in all databases.</p>
<p><code></p>
<pre class="prettyprint" lang="sql">
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
GO

If Exists (Select * From sys.objects Where object_id = object_id(N'dbo.InputBuffer') AND type in (N'FN', N'IF', N'TF', N'FS', N'FT'))
	Drop Function dbo.InputBuffer
GO

Create Function dbo.InputBuffer(@spid int) Returns varChar(max) As Begin
	Declare @code varChar(max)

	Select
		@code = SubString(
			st.text,
			(er.statement_start_offset / 2)+1,
			((Case er.statement_end_offset When -1 Then DataLength(st.text) Else er.statement_end_offset End - er.statement_start_offset) / 2) + 1
		)
	From
		sys.dm_exec_requests As er Cross Apply
		sys.dm_exec_sql_text(er.sql_handle) As st
	Where
		er.session_id = @spid;

	Return @code
End
</pre>
<p></code></p>
<h3>Caveat Emptor (sys.dm_exec_requests)</h3>
<p>There is one important difference between the code presented here, and DBCC.  Checking the input buffer through the database command console gives you the last command received on any open connection.  On the other hand, <i style="color: blue;">sys.dm_exec_requests</i> DMV only tracks queries that are <i>currently</i> executing.  This is a subtle distinction, but can be a very important one.</p>
<p>If somebody opens a query window in SSMS or Query Analyzer, runs an update query, and then doesn&#8217;t close the window once the transaction commits, DBCC will return the update query, but the function I&#8217;m presenting will not.</p>
<h3>Alternate Version</h3>
<p>Often, it&#8217;s useful to see NULL returned as an indicator that a given connection is dormant, but, sometimes what&#8217;s needed is the behavior from DBCC.  In those cases, the code below is a better fit.</p>
<p><code></p>
<pre class="prettyprint" lang="sql">
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
GO

If Exists (Select * From sys.objects Where object_id = object_id(N'dbo.InputBuffer2') AND type in (N'FN', N'IF', N'TF', N'FS', N'FT'))
	Drop Function dbo.InputBuffer2
GO

Create Function dbo.InputBuffer2(@spid int) Returns varChar(max) As Begin
	Declare @code varChar(max)

	Select
		@code = st.text
	From
		sys.dm_exec_connections As ec Cross Apply
		sys.dm_exec_sql_text(ec.most_recent_sql_handle) As st
	Where
		ec.session_id = @spid;

	Return @code
End
</pre>
<p></code></p>
<p>You might instead want to use a nullable input parameter <i style="color: blue;">(@spid int, @exactBehavior bit = 1)</i>, or simply to deploy only whichever version of the code does what you want.</p>
<p>In the next episode, we&#8217;ll look at <a href="http://dev.forrestcroce.com/dbo-query-plan-function/2009-08-19/">how to get the query plan for a transaction</a> running against the server.</p>
]]></content:encoded>
			<wfw:commentRss>http://dev.forrestcroce.com/dbo-inputbuffer-function/2009-08-17/feed/</wfw:commentRss>
		</item>
		<item>
		<title>A Debug Stopwatch (In C#)</title>
		<link>http://dev.forrestcroce.com/a-debug-stopwatch-in-c/2009-02-07/</link>
		<comments>http://dev.forrestcroce.com/a-debug-stopwatch-in-c/2009-02-07/#comments</comments>
		<pubDate>Sat, 07 Feb 2009 00:20:46 +0000</pubDate>
		<dc:creator></dc:creator>
		
		<category><![CDATA[Open Source]]></category>

		<category><![CDATA[Performance]]></category>

		<category><![CDATA[code]]></category>

		<category><![CDATA[debugging]]></category>

		<category><![CDATA[testing]]></category>

		<guid isPermaLink="false">http://dev.forrestcroce.com/?p=44</guid>
		<description><![CDATA[Time is of the utmost importance to almost any performance test, but, in .net, it can require a bit of scaffolding code.  A triplet of C# classes can make short work of measuring performance, and of collating and persisting the results, in a handy XML format.
In the wild, this is often done with code [...]]]></description>
			<content:encoded><![CDATA[<p>Time is of the utmost importance to almost any performance test, but, in .net, it can require a bit of scaffolding code.  A triplet of C# classes can make short work of measuring performance, and of collating and persisting the results, in a handy XML format.</p>
<p>In the wild, this is often done with code similar to the following:</p>
<pre class="prettyprint" lang="C#">   Stopwatch sw = new Stopwatch();

   sw.Start();
   // Do some work here
   sw.Stop();

   Debug.WriteLine(sw.Elapsed.TotalMilliseconds.ToString();</pre>
<p>This is hardly the end of the world, but it&#8217;s a bit cumbersome, especially over the course of many tests.  Perhaps a more natural construction would be:</p>
<pre class="prettyprint" lang="C#">   using (DebugStopwatch countIndexOf = new DebugStopwatch("IndexOf")) {
      // Do some work here
   }</pre>
<p>&#8230; with the results being harvested later.  The literal text &#8220;IndexOf&#8221; can be replaced with any label that will be meaningful when you analyze the timing data.  Persistence of test results is accomplished through the magic of static classes.<span id="more-44"></span></p>
<p>While run time is almost always the most important performance metric at the end of the day, it&#8217;s often more useful to know the start and end time-stamps.  In situations when other running code can affect your results, knowing <em>when</em>, and not just how long, your test ran can help you make better sense of the results.  You can correlate tests to best and worst case scenarios, if you know when other, impactful things happened.</p>
<p>A final note:  this library commits a cardinal sin, and builds XML with a StringBuilder.  There are a few reasons for this ( performance and simplicity of the code ), and this is a very particular situation;  only numbers will ever be output, so no entities could possibly corrupt a document.</p>
<pre class="prettyprint" lang="C#">namespace ForrestCroce.Logic {
      public class BenchmarkState {
            DateTime started, ended;
            long startingWorkingSet, endingWorkingSet;
            DebugStopwatch sw;

            internal BenchmarkState(DebugStopwatch creator) {
                  startingWorkingSet = Environment.WorkingSet;
                  sw = creator;
                  started = DateTime.Now;
            }

            internal void Conclude() {
                  ended = DateTime.Now;
                  endingWorkingSet = Environment.WorkingSet;
            }

            public string XmlFragment {
                  get {
                        StringBuilder sb = new StringBuilder();
                        sb.AppendLine("\t");
                        sb.AppendLine("\t\t");
                        sb.AppendLine("\t\t\t" + started.ToString() + "");
                        sb.AppendLine("\t\t\t" + ended.ToString() + "");
                        sb.AppendLine("\t\t\t" + sw.Elapsed.TotalMilliseconds.ToString() + "");
                        sb.AppendLine("\t\t");
                        sb.AppendLine("\t\t");
                        sb.AppendLine("\t\t\t" + startingWorkingSet.ToString() + "");
                        sb.AppendLine("\t\t\t" + endingWorkingSet.ToString() + "");
                        sb.AppendLine("\t\t");
                        sb.AppendLine("\t");
                        return sb.ToString();
                  }
            }
      }

      public class DebugStopwatch : Stopwatch, IDisposable {
            BenchmarkState status;
            string label;

            public DebugStopwatch() {
                  status = new BenchmarkState(this);
                  StopwatchManager.Add(this);
                  Start();
            }

            public DebugStopwatch(string debugLabel) {
                  label = debugLabel;
                  status = new BenchmarkState(this);
                  StopwatchManager.Add(this);
                  Start();
            }

            public void Dispose() {
                  Stop();
            }

            public new void Stop() {
                  base.Stop();
                  status.Conclude();

                  string text = string.IsNullOrEmpty(label) ? DateTime.Now.ToString() : label + ": ";
                  text += (Elapsed.TotalSeconds + Elapsed.TotalMilliseconds).ToString("#,##0.000") + " ms";
                  System.Diagnostics.Debug.WriteLine(text);
            }

            public BenchmarkState State { get { return status; } }

            public string Label { get { return label; } set { label = value; } }
      }

      public static class StopwatchManager {
            static Dictionary byInstanceID = new Dictionary();

            public static DebugStopwatch Create(string label) {
                  DebugStopwatch sw = new DebugStopwatch(label);
                  return sw;
            }

            public static void Add(DebugStopwatch sw) {
                  int id = byInstanceID.Count;
                  byInstanceID.Add(id, sw.State);
            }

            public static string Xml {
                  get {
                        StringBuilder sb = new StringBuilder();
                        sb.AppendLine("");

                        foreach (KeyValuePair item in byInstanceID)
                              sb.Append(item.Value.XmlFragment);

                        sb.AppendLine("");
                        return sb.ToString();
                  }
            }
      }

}</pre>
]]></content:encoded>
			<wfw:commentRss>http://dev.forrestcroce.com/a-debug-stopwatch-in-c/2009-02-07/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Normalizer of Web Pages, Qualifier of URLs</title>
		<link>http://dev.forrestcroce.com/normalizer-of-web-pages-qualifier-of-urls/2008-12-09/</link>
		<comments>http://dev.forrestcroce.com/normalizer-of-web-pages-qualifier-of-urls/2008-12-09/#comments</comments>
		<pubDate>Tue, 09 Dec 2008 06:09:18 +0000</pubDate>
		<dc:creator></dc:creator>
		
		<category><![CDATA[Open Source]]></category>

		<category><![CDATA[Web]]></category>

		<category><![CDATA[code]]></category>

		<category><![CDATA[scraping]]></category>

		<guid isPermaLink="false">http://dev.forrestcroce.com/?p=6</guid>
		<description><![CDATA[Relative paths look like /images/filename.jpeg, explaining the relationship between the current location and the resource.  Fully qualified paths are complete addresses, and look like http://domain.com/images/filename.jpg.
Sometimes you need to translate between the two.  Think of absolute urls as the third normal form of the web.
The complete solution has 138 lines in two classes, but this includes [...]]]></description>
			<content:encoded><![CDATA[<p>Relative paths look like <span style="color: #ff0000;"><em><span style="&quot;color: #999999; font-family: &quot;;">/images/filename.jpeg</span></em></span>, explaining the relationship between the current location and the resource.  Fully qualified paths are complete addresses, and look like <span style="color: #ff0000;"><em><span style="&quot;color: #999999; font-family: &quot;;">http://domain.com/images/filename.jpg</span></em></span>.</p>
<p>Sometimes you need to translate between the two.  Think of absolute urls as the third normal form of the web.</p>
<p>The complete solution has 138 lines in two classes, but this includes fetching the content from the internet.  Filling in a host name and path for each relative link is easy. You can download the full implementation</p>
<ul>
<li><strong><a title="Code to fully qualify urls" href="http://dev.forrestcroce.com/source-code/Resource-Qualifier.html">ResourceQualifier.cs</a></strong></li>
<li><strong><a title="General web code" href="http://dev.forrestcroce.com/source-code/Web-Utility.html">WebUtility.cs</a></strong></li>
</ul>
<p>The juicy bits are below:<span id="more-6"></span></p>
<pre class="prettyprint" lang="C#">public string Code() {
	HtmlDocument doc = WebUtility.GetPage(originalHtml);
	RecursiveQualifier(doc.DocumentNode);

	return cleanHtml = doc.DocumentNode.OuterHtml;
}

private void RecursiveQualifier(HtmlNode node) {
	QualifyNode(node);

	foreach (HtmlNode child in node.ChildNodes)
		RecursiveQualifier(child);
}

private void QualifyNode(HtmlNode node) {
	if (node.HasAttributes)
		foreach (HtmlAttribute a in node.Attributes)
			if (string.Compare(a.Name, "src", StringComparison.OrdinalIgnoreCase) == 0 || string.Compare(a.Name, "href", StringComparison.OrdinalIgnoreCase) == 0)
				if (Uri.IsWellFormedUriString(a.Value, UriKind.RelativeOrAbsolute) &amp;&amp; !(new Uri(a.Value, UriKind.RelativeOrAbsolute).IsAbsoluteUri))
					a.Value = QualifyUrl(a.Value).ToString();
}

public static Uri Qualify(string baseUri, string relativePath) {
	if (Uri.IsWellFormedUriString(relativePath, UriKind.Absolute))
		return new Uri(relativePath);

	if (!Uri.IsWellFormedUriString(baseUri, UriKind.Absolute))
		return null;

	Uri b = new Uri(baseUri, UriKind.RelativeOrAbsolute);

	return new Uri(b, relativePath);
}</pre>
<p><strong>Note</strong>:  <em>The Qualify methods don&#8217;t agree, but download the source code, and you&#8217;ll see why.</em></p>
<p>All resources that can be called out to in html use either a <span class="codeKeyword">src</span> or an <span class="codeKeyword">href</span> attribute:  images, flash movies, style sheets, scripts, music, etc.  <a href="http://xhtml.com/en/future/x-html-5-versus-xhtml-2/#x2-cool-hyperlink" target="_blank">Xhtml 2</a> allows any element to be a link, so finding particular tag names doesn&#8217;t work.  Fortunately, <a href="http://www.codeplex.com/htmlagilitypack" target="_blank">Html Agility Pack</a> comes to the rescue;  this gem is the XmlDocument of sloppy, malformed html.</p>
<p>Recursion lets you start at the root node and walk down the tree, checking every element for the attributes we&#8217;re interested in, and &#8220;fix&#8221; the links.  The <span class="codeKeyword">Uri</span> class takes care of what would otherwise be tedious string parsing with &#8220;<em><span style="&quot;color: #999999; font-family: &quot;;">/folder</span></em>&#8221; and &#8220;<span style="&quot;color: #999999; font-family: &quot;;"><em>../../parent/path</em></span>&#8221; in urls.</p>
]]></content:encoded>
			<wfw:commentRss>http://dev.forrestcroce.com/normalizer-of-web-pages-qualifier-of-urls/2008-12-09/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Hello world!</title>
		<link>http://dev.forrestcroce.com/hello-world/2008-11-30/</link>
		<comments>http://dev.forrestcroce.com/hello-world/2008-11-30/#comments</comments>
		<pubDate>Mon, 01 Dec 2008 04:11:39 +0000</pubDate>
		<dc:creator></dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://dev.forrestcroce.com/?p=1</guid>
		<description><![CDATA[Another blog devoted to research and development in the software world;  there have been worse ideas, but there have been better ones, too&#8230;
The open source will come slowly, but do innovative and very useful things.  General ideas, findings, and snippets of code will also find their way to these pages.  Stay tuned.
C# and Microsoft SQL [...]]]></description>
			<content:encoded><![CDATA[<p>Another blog devoted to <a title="Research" href="http://research.forrestcroce.com/" target="_blank">research</a> and development in the software world;  there have been worse ideas, but there have been better ones, too&#8230;</p>
<p>The open source will come slowly, but do innovative and very useful things.  General ideas, findings, and snippets of code will also find their way to these pages.  Stay tuned.</p>
<p>C# and Microsoft SQL Server will be the general focus of this blog, although the topics will stray.</p>
]]></content:encoded>
			<wfw:commentRss>http://dev.forrestcroce.com/hello-world/2008-11-30/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
