<?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/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Christopher H. Laco</title>
	<atom:link href="http://chrislaco.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://chrislaco.com</link>
	<description></description>
	<lastBuildDate>Wed, 28 Jul 2010 00:21:48 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Book Review: Catalyst 5.8: The Perl MVC Framework</title>
		<link>http://chrislaco.com/reviews/catalyst-5-8-the-perl-mvc-framework/</link>
		<comments>http://chrislaco.com/reviews/catalyst-5-8-the-perl-mvc-framework/#comments</comments>
		<pubDate>Wed, 28 Jul 2010 00:17:52 +0000</pubDate>
		<dc:creator>claco</dc:creator>
				<category><![CDATA[Reviews]]></category>

		<guid isPermaLink="false">http://chrislaco.com/?p=256</guid>
		<description><![CDATA[Disclaimer: I was contacted by Packt Publishing about reviewing this book and was sent a free copy to do so. Background A long time ago in a land far far away (2004), I started programming in Perl as my non-MS &#8230; <a href="http://chrislaco.com/reviews/catalyst-5-8-the-perl-mvc-framework/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><a href="/wp-content/uploads/2010/07/Catalyst-5.8_Front-cover.jpg"><img class="alignleft size-thumbnail wp-image-257" title="Catalyst 5.8 Front Cover" src="http://chrislaco.com/wp-content/uploads/2010/07/Catalyst-5.8_Front-cover-121x150.jpg" alt="" width="121" height="150" /></a><em>Disclaimer: I was contacted by Packt Publishing about reviewing <a href="https://www.packtpub.com/catalyst-5-8-the-perl-mvc-framework/book?utm_source=chrislaco.com&amp;utm_medium=bookrev&amp;utm_content=blog&amp;utm_campaign=mdb_003900">this book</a> and was sent a free copy to do so.</em></p>
<h2>Background</h2>
<p>A long time ago in a land far far away (2004), I started programming in Perl as my non-MS language of choice. It all started innocently enough by taking over others&#8217; CPAN dists, then eventually creating my own shopping cart system intertwined with Catalyst 5.6/5.7 and DBIx::Class.</p>
<p>Then a few years ago as more and more Rails opportunities came along and as ASP.NET MVC 1.0 came into existence, I slowly migrated away from Perl as my primary language. This review is primarily from the perspective of someone who is still fairly familiar with most of Catalyst and while I&#8217;m familiar with what Moose has to offer, I haven&#8217;t ever done any projects that make use of it.</p>
<p>Enough about me. On with the show!</p>
<h2>The Good</h2>
<p>This book does a pretty good job of covering all of the basics for people new to Catalyst from installation and app creation to using the most common ORM (DBIX::Class), testing and deployment. There always seems to be a debate about what examples books should use for beginners: best practices vs. simple examples. This book does a pretty good job of finding that middle ground in that area. For example, some of the templating examples aren&#8217;t the greatest when it comes to reuse, but the prevention of XSS and security/html encoding are explained fro the beginning.</p>
<p>I&#8217;m also fond of this books treatment of models. While it doesn&#8217;t explicitly mention &#8220;domain model&#8221; vs. &#8220;data model&#8221; arguments, it does a great job of having the user think about having their &#8220;models&#8221; be reusable and working outside of Catalyst (like in a pl script) before applying &#8220;glue&#8221; to use those models inside of Catalyst. This is reinforced by creating a few utility scripts to prepopulate the database with data before using that data in Catalyst itself as well as creating non database models for use as Catalyst &#8220;models&#8221;.</p>
<p>This book spends a fair amount of time talking about the most common features of DBIx::Class as well as presenting options to do the same things in DBI without an ORM for contrast. This book feels like it&#8217;s really 35% of a DBIx::Class book. I think that&#8217;s a good thing.</p>
<p>Another good area for me was Authentication/Authorization. Those two things aren&#8217;t the same and a lot of framework book gloss over that fact. This book did a good job of explaining the difference and showing how to implement each part.</p>
<p>One of my favorite chapters of the book was the &#8220;Hot Web Topic&#8221; area which covered REST  and AJAX. While most people are familiar with these things, it&#8217;s nice that a beginners book covers them. My favorite nugget though is Jemplate, which allows you to essentially reuse templates from your views within your AJAX handlers. While everyone seems to talk about AJAX, I&#8217;ve not seem too many people take up the topic of templating your dynamically generated HTML for the sake of DRY.</p>
<p>Last but not least, it&#8217;s always nice to be able to download the source code for the examples included in the book.</p>
<h2>The Bad</h2>
<p>Like all books, there are some things that feel like they were glossed over for the sake or brevity that would&#8217;ve have made for a more complete book for Catalyst beginners.</p>
<p>First, in the tempting examples, this book uses an admittedly &#8220;unsupported&#8221; module called TTSite, which have the common header/footer/wrapper type issues already implemented. I think it would have been better to walk users through setting up those things using the default view and the <em>wrapper</em> options in Template Toolkit.</p>
<p>This is a minor nit and not really a bad thing, but it would&#8217;ve been nice for the book to talk a little more about the use of <em>go()</em> vs <em>forward()</em> when transferring between actions.</p>
<p>My last complaint is one of linking to CPAN. CPAN modules often change hands or are updated by many people. Almost all of the links to CPAN in this book link to a specific persons account when they should probably be linking to the dist instead:</p>
<pre><code># Current

http://search.cpan.org/~bobtfish/Catalyst-Action-REST-0.85/

# Better

http://search.cpan.org/dist/Catalyst-Action-REST-0.85/</code></pre>
<h2>The Ugly</h2>
<p>The worst part about this book for me was the code formatting. The wrapping of long lines isn&#8217;t very readable and for the most part it feels like someone formatted code using Microsoft Word. I haven&#8217;t ready any other Catalyst books for comparison, but the code formatting in my Rails books are much easier on the eyes to read. I don&#8217;t know if that&#8217;s due to language differences, color/font choices, or if maybe putting the code inside of images would help.</p>
<h2>Conclusions</h2>
<p>Without having read other Catalyst books, I do think this book is a good resource for beginners of Catalyst MVC development. People already familiar with an older version of Catalyst might not find too many surprises, but there are a few nuggets of information about Catalyst+Moose and a good overview of DBIx::Class to refresh your brain.</p>
]]></content:encoded>
			<wfw:commentRss>http://chrislaco.com/reviews/catalyst-5-8-the-perl-mvc-framework/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Clerbtime &amp; Moving Forward</title>
		<link>http://chrislaco.com/events/clerbtime-moving-forward/</link>
		<comments>http://chrislaco.com/events/clerbtime-moving-forward/#comments</comments>
		<pubDate>Fri, 25 Jun 2010 03:39:17 +0000</pubDate>
		<dc:creator>claco</dc:creator>
				<category><![CDATA[Events]]></category>

		<guid isPermaLink="false">http://chrislaco.com/?p=254</guid>
		<description><![CDATA[Had another great time at the Clerb &#8220;south&#8221; Meetup tonight in Akron hosted by Blue Frog Gaming. Always nice to see more locals at every new meetup. Beers and such afterwords doesn&#8217;t hurt either. Going to these meetups are always &#8230; <a href="http://chrislaco.com/events/clerbtime-moving-forward/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Had another great time at the Clerb &#8220;south&#8221; Meetup tonight in Akron hosted by Blue Frog Gaming. Always nice to see more locals at every new meetup. Beers and such afterwords doesn&#8217;t hurt either.</p>
<p>Going to these meetups are always humbling. I always leave feeling like I know nothing, but they also provide good motivation to learn something new. It also highlights how much people can do in a day and how much I&#8217;m not getting things done. I need to fix that somehow. Too much to learn and do. Too much opportunity being missed.</p>
<p>Things I would like to accomplish in the next 180 days (in no certain order):</p>
<ul>
<li>Rework JanKenPon</li>
<li>Make JanKenPon a Facebook App</li>
<li>Finish HelpNear.Me Web/iPhone version</li>
<li>Get an iPad <img src='http://chrislaco.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </li>
<li>Make an iPhone/iPad game (HTML5?): Dock Crane Madness</li>
<li>Rebrand my blog/logo/cards</li>
</ul>
<p><span style="font-size: medium;">Nothing there is terribly difficult. I just need to sack up and do it. For rizzle.</span></p>
]]></content:encoded>
			<wfw:commentRss>http://chrislaco.com/events/clerbtime-moving-forward/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Advance2030 Weekend</title>
		<link>http://chrislaco.com/events/advance2030-weekend/</link>
		<comments>http://chrislaco.com/events/advance2030-weekend/#comments</comments>
		<pubDate>Tue, 02 Mar 2010 02:44:31 +0000</pubDate>
		<dc:creator>claco</dc:creator>
				<category><![CDATA[Events]]></category>

		<guid isPermaLink="false">http://chrislaco.com/?p=246</guid>
		<description><![CDATA[This last weekend, I was fortunate enough to attend the Advance2030 Web Development Weekend held on the LeanDog boat and spend some time with a great bunch of web folk from the area. This included sitting next to Joe Fiorini &#8230; <a href="http://chrislaco.com/events/advance2030-weekend/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>This last weekend, I was fortunate enough to attend the <a href="http://advance2030.wordpress.com/">Advance2030 Web Development Weekend</a> held on the LeanDog boat and spend some time with a great bunch of web folk from the area. This included sitting next to Joe Fiorini and Nate Klaiber and getting schooled in Rails on a nonstop basis. While the weekend was a great experience, I wanted to get some thoughts up about it while they&#8217;re still fresh.</p>
<p>Friday night was a great start. After a group gathering to go over the site, we split up into pairs to get a set of story cards created. This was a relatively new experience for me in terms of planning a development cycle.  After tinkering with Cucumber over the last month, it seems to fit right into the Agile/BDD way and it&#8217;s something that certainly helps me focus on knowing what I plan on doing before I start coding.</p>
<p>Saturday was a different story. I literally spent the first 5 hours or so struggling with the Rails environment chosen for the weekend. I&#8217;m no Rails expert and I understand why some gems were chosen, like Bundler in a forward looking approach to the impending Rails3 release.  But it seems a few of us had issues with it in combination with Authlogic because of which gems loaded first and if we had previously installed any gems using sudo instead of installing them into local gems. When it&#8217;s all said and done, I could run rake spec but Command-R in Textmate never worked right. Even after moving on I spent a lot of time dealing with schema.rb merge conflicts when pulling from upstream. This isn&#8217;t a terribly surprise given that file is a bottleneck of sorts when you have a lot of people adding migrations in rapid fire.</p>
<p>All in all, I got nothing done Saturday and I&#8217;m not proud of it. I lost my will to live at around 3PM. If I were to start an event like this, I would give serious thought to removing some of these pain points for the developers, esp for people who aren&#8217;t Rails experts. Stick to the stock Rails gem management setup. The less gems you load, the less shenanigans you have to fight, esp ones that try and manage gems/paths. At list for the first iteration. Also, I would either get the migrations/schema done before the event, or at least funnel migration creation through 1-2 people. Let everyone else mock their way down from the outside in.</p>
<p>Sunday was awesome. I did what I should&#8217;ve done Saturday. Grab a card and get something out the door and stop worrying if I&#8217;m doing it &#8220;right&#8221; the first time. It&#8217;s easier to re-factor than it is to create. Move forward. By the end of the night I managed to get a calendar page up, styled with the help of Parag including next/previous and month dropdown selection support.</p>
<p>I&#8217;m definitely looking forward to the next event like this. Hopefully by then I can get my current Rails project done so I won&#8217;t suck so much at the next event. <img src='http://chrislaco.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://chrislaco.com/events/advance2030-weekend/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>WebFormViewEngine Path Defaults Seem Broken</title>
		<link>http://chrislaco.com/microsoft/webformviewengine-path-defaults-seem-broken/</link>
		<comments>http://chrislaco.com/microsoft/webformviewengine-path-defaults-seem-broken/#comments</comments>
		<pubDate>Thu, 21 Jan 2010 03:54:07 +0000</pubDate>
		<dc:creator>claco</dc:creator>
				<category><![CDATA[Microsoft]]></category>

		<guid isPermaLink="false">http://chrislaco.com/?p=239</guid>
		<description><![CDATA[This post is about 60% fact and 40% opinion. Not a bad ratio. I&#8217;ve been working a lot in ASP.NET MVC lately building up a set of classes to be reused across multiple sites in the near future. A few &#8230; <a href="http://chrislaco.com/microsoft/webformviewengine-path-defaults-seem-broken/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>This post is about 60% fact and 40% opinion. Not a bad ratio. I&#8217;ve been working a lot in ASP.NET MVC lately building up a set of classes to be reused across multiple sites in the near future. A few of these legos are small view classes that inherit from <code>WebFormViewEngine</code>. They all do small things, like adding additional file search paths, loading views from resources and fetching views from remote storage. Since you can stack view engines in <code>ViewEngines.Engines</code>, you can add and number of these engines together to get the functionality you want on a site per site basis. First engine to claim it can service a view wins. Nothing special there really.</p>
<p>I stumbled across something today that seems obvious in retrospect that leads me to the opinion that the default view/partial view search patterns are broken. If you crack open Reflector.NET and point it towards <code>WebFormViewEngine</code>, you&#8217;ll see that <code>ViewLocationFormats</code> and <code>PartialViewLocationFormats</code> are declared the same:</p>
<pre style="padding-left: 30px;">~/Views/{1}/{0}.aspx</pre>
<pre style="padding-left: 30px;">~/Views/{1}/{0}.ascx</pre>
<pre style="padding-left: 30px;">~/Views/Shared/{0}.aspx</pre>
<pre style="padding-left: 30px;">~/Views/Shared/{0}.ascx</pre>
<p><span style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px; white-space: normal; font-size: 13px;">In other words, for the <code>Index</code> action on the <code>Home</code> controller, the following paths are searched:</span></p>
<pre style="padding-left: 30px;">~/Views/Home/Index.aspx</pre>
<pre style="padding-left: 30px;">~/Views/Home/Index.ascx</pre>
<pre style="padding-left: 30px;">~/Views/Shared/Index.aspx</pre>
<pre style="padding-left: 30px;">~/Views/Shared/Index.ascx</pre>
<p>This all seems well and good until you happen to have a partial view that has the same name as an action that either happens to be shared, or the parti is being overridden in the local controllers folder. Here&#8217;s a somewhat plausible example: A <code>Search</code> controller with an <code>Items</code> action:</p>
<pre style="padding-left: 30px;">~/Views/Search/Items.aspx</pre>
<pre style="padding-left: 30px;">    (the view page for the Items action)</pre>
<pre style="padding-left: 30px;">~/Views/Home/Index.ascx</pre>
<pre style="padding-left: 30px;">    (possibly an items partial view customized just for this controller/action)</pre>
<pre style="padding-left: 30px;">~/Views/Shared/Items.ascx</pre>
<pre style="padding-left: 30px;">    (the shared partial view to render items in many controllers/actions/views)</pre>
<p>This is where the problems start. By default, a call to <code>RenderPartial("Items")</code> within the <code>Items.aspx</code> page is going to find the <code>Items.aspx</code> file first and not the <code>Items.ascx</code>. I&#8217;ve never ever seen anyone in the wild put <em>partial views</em> in an <em>aspx</em> file nor have I ever seen anyone put a full <em>action view</em> in an <em>ascx</em> file. So why on earth did they all them to be interchangeable in the location paths? Broken I say. Broken.</p>
<p>The good news is that it&#8217;s super easy to tweak these kinds of things in ASP.NET MVC. Inherit from <code>WebFormViewEngine</code> and set your own <code>ViewLocationFormats</code> and <code>PartialViewLocationFormats</code>. I my case I decided to force the issue explicitly. <code>ViewLocationFormats</code> <em>only looks for aspx</em> files and <code>PartialViewLocationFormats</code> <code>only look for ascx</code> files. Now we can override shared partial views locally in controller folders without worrying about name collisions.</p>
]]></content:encoded>
			<wfw:commentRss>http://chrislaco.com/microsoft/webformviewengine-path-defaults-seem-broken/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Template Toolkit for .NET</title>
		<link>http://chrislaco.com/software/template-toolkit-for-net/</link>
		<comments>http://chrislaco.com/software/template-toolkit-for-net/#comments</comments>
		<pubDate>Fri, 12 Jun 2009 23:11:05 +0000</pubDate>
		<dc:creator>claco</dc:creator>
				<category><![CDATA[Software]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[antlr]]></category>
		<category><![CDATA[ast]]></category>
		<category><![CDATA[lexer]]></category>
		<category><![CDATA[parser]]></category>
		<category><![CDATA[template toolkit]]></category>
		<category><![CDATA[tt]]></category>

		<guid isPermaLink="false">http://chrislaco.com/?p=231</guid>
		<description><![CDATA[A while back I got the urge the waste time on yet another project. This time, it&#8217;s a version of Template Toolkit for .NET. As usual, you can find the project on GitHub. Not knowing anything about what it takes &#8230; <a href="http://chrislaco.com/software/template-toolkit-for-net/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>A while back I got the urge the waste time on yet another project. This time, it&#8217;s a version of  <a href="http://template-toolkit.org/">Template Toolkit</a> for .NET. As usual, you can find the project on <a href="http://github.com/claco/tt.net/">GitHub</a>.</p>
<p>Not knowing anything about what it takes to convert a template language to .NET I started from ground up learning how to use ANTLR to create a lexer/parser automatically from a grammar definition. As if that wasn&#8217;t enough, my parser output is an Abstract Syntax Tree, which I then use another grammar to template it into C# code using StringTemplate templates, which ANTLR supports natively.</p>
<p>It&#8217;s slow going, but I&#8217;m learning a lot along the way. At some point I&#8217;m going to output VB.NET and it still needs a lot of work for compilation, dll caching and such. The code is in a pre beta state, but it does support basic GET/SET/DEFAULT/IF statements and I&#8217;m slowly adding more as I get more comfortable with ANTLR.</p>
]]></content:encoded>
			<wfw:commentRss>http://chrislaco.com/software/template-toolkit-for-net/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Writing ReSharper 4.5.x Macros</title>
		<link>http://chrislaco.com/articles/writing-resharper-45x-macros/</link>
		<comments>http://chrislaco.com/articles/writing-resharper-45x-macros/#comments</comments>
		<pubDate>Mon, 20 Apr 2009 00:48:45 +0000</pubDate>
		<dc:creator>claco</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[macros]]></category>
		<category><![CDATA[resharper]]></category>

		<guid isPermaLink="false">http://chrislaco.com/?p=212</guid>
		<description><![CDATA[While working on the MVC Marathon, I decided to try out ReSharper and write some good templates to make my time unit testing in ASP.NET MVC a little quicker. I soon realized that I needed a macro that would turn &#8230; <a href="http://chrislaco.com/articles/writing-resharper-45x-macros/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>While working on the MVC Marathon, I decided to try out ReSharper and write some good templates to make my time unit testing in ASP.NET MVC a little quicker. I soon realized that I needed a macro that would turn the unit test class name (HomeControllerTests) into the name of the controller being tested (HomeController).</p>
<p><span id="more-212"></span>Since ReSharper only has a few macros that will make copies of other template variables, I started scouring the internet for clues and found <a href="http://mindstudies.psy.soton.ac.uk/dmitri/blog/index.php/archives/202">this post</a>. It&#8217;s a little outdate for ReSharper for 4.5, so here&#8217;s what I had to do to make my custom macro.</p>
<p>You can download the source or fork your own on <a href="http://github.com/claco/resharpermacros/">GitHub</a>.</p>
<p><!--more--></p>
<h2>Creating the Macro</h2>
<ol>
<li>Create a new C# class library project.</li>
<li>Add references to the following dlls:
<pre class="brush:csharp">JetBrains.Platform.ReSharper.UI.dll
JetBrains.ReSharper.Feature.Services.dll</pre>
</li>
<li>Add a new class to your project and mark it with the Macro attribute and implement the IMacro interface:
<pre class="brush:csharp">using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using JetBrains.ReSharper.Feature.Services.LiveTemplates.Macros;
using JetBrains.ReSharper.Feature.Services.LiveTemplates.Hotspots;

namespace ChrisLaco.ReSharper.Macros
{
    // {#0:pattern}, etc are arguments that are passed to EvaluateQuickResult arguments[]
    [Macro("applyRegex", ShortDescription = "Replace string matching {#0:pattern} with {#1:string} in {#2:variable}", LongDescription = "Applies regex to replace value in another template variable.")]
    class ApplyRegexMacro : IMacro
    {
        #region IMacro Members

        public string EvaluateQuickResult(IHotspotContext context, IList&lt;string&gt; arguments)
        {
            if (arguments.Count != 3)
            {
                return null;
            }
            else
            {
                try
                {
                    // Using the regex argument, replate the value of the specified template variable with the specified string
                    var result = Regex.Replace(arguments[2], arguments[0], arguments[1], RegexOptions.IgnoreCase);

                    return result;
                }
                catch (Exception e)
                {
                    return "&lt;" + e.Message + "&gt;";
                }
            }
        }

        public HotspotItems GetLookupItems(IHotspotContext context, IList&lt;string&gt; arguments)
        {
            return null;
        }

        public string GetPlaceholder()
        {
            return "a";
        }

        public bool HandleExpansion(IHotspotContext context, IList&lt;string&gt; arguments)
        {
            return false;
        }

        // Must return the same # of parameters declared in the Macro
        public ParameterInfo[] Parameters
        {
            get
            {
                return new[] { new ParameterInfo(ParameterType.String), new ParameterInfo(ParameterType.String), new ParameterInfo(ParameterType.VariableReference) };
            }
        }

        #endregion
    }
}</pre>
</li>
<li>In AssemblyInfo.cs, apply assembly attributes for the ReSharper plugin manager:
<pre class="brush:csharp">using System.Reflection;
using System.Runtime.InteropServices;
using JetBrains.UI.Application.PluginSupport;

[assembly: PluginTitle("ChrisLaco.ReSharper.Macros")]
[assembly: PluginDescription("Provides additional template macros: ApplyRegexMacro.")]
[assembly: PluginVendor("Christopher H. Laco")]</pre>
<p>This information will be displayed in the ReSharper -&gt; Plugins dialag:</p>
<p><a href="http://chrislaco.com/wp-content/uploads/2009/04/picture-1.png"><img class="aligncenter size-medium wp-image-216" title="ReSharper Plugin Manager" src="http://chrislaco.com/wp-content/uploads/2009/04/picture-1-300x176.png" alt="ReSharper Plugin Manager" width="300" height="176" /></a></li>
<li>To install plugin, simply copy the compiled dll into one of the follow directories:
<pre class="brush::csharp">C:\Documents and Settings\username\Application Data\JetBrains\ReSharper\v4.5\vs9.0\Plugins
C:\Program Files\JetBrains\ReSharper\v4.5\Bin\Plugins</pre>
</li>
</ol>
<h2>Using the Macro</h2>
<ol>
<li>Select the macro from the list of available macros:<a href="http://chrislaco.com/wp-content/uploads/2009/04/picture-2.png"><img class="aligncenter size-medium wp-image-217" title="Choose Macro" src="http://chrislaco.com/wp-content/uploads/2009/04/picture-2-279x300.png" alt="Choose Macro" width="279" height="300" /></a></li>
<li>Click on the macro variables to set them:<a href="http://chrislaco.com/wp-content/uploads/2009/04/picture-3.png"><img class="aligncenter size-medium wp-image-218" title="Set Macro Variables" src="http://chrislaco.com/wp-content/uploads/2009/04/picture-3-300x235.png" alt="Set Macro Variables" width="300" height="235" /></a></li>
<li>Finish up the template text and savr your changes:<a href="http://chrislaco.com/wp-content/uploads/2009/04/picture-4.png"><img class="aligncenter size-medium wp-image-219" title="Apply Macro to Template" src="http://chrislaco.com/wp-content/uploads/2009/04/picture-4-300x125.png" alt="Apply Macro to Template" width="300" height="125" /></a></li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://chrislaco.com/articles/writing-resharper-45x-macros/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Macbook Pro Go Boom</title>
		<link>http://chrislaco.com/apple/macbook-pro-go-boom/</link>
		<comments>http://chrislaco.com/apple/macbook-pro-go-boom/#comments</comments>
		<pubDate>Thu, 02 Apr 2009 00:19:57 +0000</pubDate>
		<dc:creator>claco</dc:creator>
				<category><![CDATA[Apple]]></category>
		<category><![CDATA[applecare]]></category>
		<category><![CDATA[lcd]]></category>
		<category><![CDATA[leakage]]></category>

		<guid isPermaLink="false">http://chrislaco.com/?p=203</guid>
		<description><![CDATA[Slowly over the last couple of weeks, my Macbook Pro started going downhill. It started with a big bad pixel in the top middle of the screen. Nothing worth pursuing since there was only one. Then Saturday while doing some &#8230; <a href="http://chrislaco.com/apple/macbook-pro-go-boom/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Slowly over the last couple of weeks, my Macbook Pro started going downhill. It started with a big bad pixel in the top middle of the screen. Nothing worth pursuing since there was only one. Then Saturday while doing some full screen editing in Textmate I noticed a rash of speckles on the right side. I thought it was dirt. Of course, it didn&#8217;t come off when I cleaned the screen.<span id="more-203"></span></p>
<p>Off I went to the Apple store Sunday to get it fixed.  Aside from the wait due to the place being packed as always, the process was pretty easy. My Genius called over another Genius and said &#8220;Hey, come look at this.&#8221;  Oh no I thought. Apparently, one thing that gets the Genius folk excited are laptops that are old but in mint condition. They seemed pleased that my old 2007 was cherry. Of course it was. I pamper the thing. The Speck case doesn&#8217;t hurt either. And it doesn&#8217;t hurt my chances of getting the screen fixed without issue as well.</p>
<p>Luckily for me, the LCD replacement was an in store repair. Once the part came in Tuesday the repair was done and they called me this evening to come pick it up.</p>
<p>Nice. Thank god I spent the $ I saved on an Apple store refurb on AppleCare. <img src='http://chrislaco.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://chrislaco.com/apple/macbook-pro-go-boom/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Monitoring Local Directories with Siphon</title>
		<link>http://chrislaco.com/articles/monitoring-local-directories-with-siphon/</link>
		<comments>http://chrislaco.com/articles/monitoring-local-directories-with-siphon/#comments</comments>
		<pubDate>Thu, 19 Mar 2009 02:00:58 +0000</pubDate>
		<dc:creator>claco</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[local directories]]></category>
		<category><![CDATA[monitor]]></category>
		<category><![CDATA[siphon]]></category>

		<guid isPermaLink="false">http://chrislaco.com/?p=183</guid>
		<description><![CDATA[This is the third in a series of posts about Siphon, a set of data monitoring utilities for .NET under the MIT license. The source code can be found on GitHub. Introduction In this article, I&#8217;ll show you how to &#8230; <a href="http://chrislaco.com/articles/monitoring-local-directories-with-siphon/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>This is the third in a series of posts about Siphon, a set of data monitoring utilities for .NET under the MIT license. The source code can be found on <a title="Siphon on GitHub" href="http://github.com/claco/siphon/">GitHub</a>.</p>
<h2><span id="more-183"></span>Introduction</h2>
<p>In this article, I&#8217;ll show you how to monitor a local directory using Siphon and go over some of the different options that are available.</p>
<h2>The Scenerio</h2>
<p>Your mission, should you chose to accept it, is to check a local file system directory for new CSV files twice a day at 8am and 3pm. Upon completion, or failure of processing each file, we will rename then move them to separate directories for a human to review. In order to achieve this, we will need to:</p>
<ol>
<li>Create a custom processor class to process our csv files</li>
<li>Configure a new monitor in app.config</li>
<li>Run the monitor</li>
</ol>
<h2>Creating a Processor</h2>
<p>In order to have Siphon process data, we must create a custom processor class. More often than not, this will probably just be an adapter  between the Siphon API and your other existing software. The only requirements for a processor in Siphon is that the class:</p>
<ol>
<li>The class must have a constructor that takes no parameters (private, protected or public)</li>
<li>The class must implement the IDataProcessor interface</li>
</ol>
<p>For the sake of me getting my C# skills up to par, we&#8217;ll use C# for this example. I&#8217;m going to assume that you have a basic understanding of starting new projects, classes, and adding references to other assemblies. Once you&#8217;ve created a new class and added a reference to System.Configuration and Siphon.dll, we want to implement the IDataProcessor interface. This consists of 3 methods: Initialize, Process and Dispose:</p>
<pre class="brush:csharp">using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ChrisLaco.Siphon;

namespace CustomProcessor
{
    public class CustomProcessor : IDataProcessor
    {
        public void Initialize(ProcessorElement config)
        {
        }

        public bool Process(IDataItem item)
        {
        }

        public void Dispose()
        {
        }
    }
}</pre>
<p>A data processor has three basic actions:</p>
<ol>
<li>Initialize the process using the configuration supplied from the service or console where this monitor is running</li>
<li>Process the new data item, returning True if it was processed successfully or False if processing failed</li>
<li>Cleanup any resources</li>
</ol>
<h3>First, a word from our sponsor about IDataItem and IDataItem&lt;T&gt;</h3>
<p>When a monitor finds new items to process, it wraps them in any number of classes that implement the IDataItem&lt;T&gt; interface. This interface exposes three properties:</p>
<ol>
<li><strong>Name</strong>: A friendly name for the data item</li>
<li><strong>GetString</strong>: The contents of the data item</li>
<li><strong>Data</strong>: The underlying data item in it&#8217;s native format</li>
</ol>
<p>What gets returned from the Data property depends on what type of data each specific monitor understands. The LocalDirectoryProcessor returns FileInfo objects, as does the FtpMonitor. The DatabaseMonitor returns TableRow objects. Some monitors, like Imap and Pop3 monitors, return simple string that also has a reference to the temp file where it&#8217;s stored. It is assumed, wisely or otherwise that the monitor and the processor have to both understand and work with the same Data types. It wouldn&#8217;t make much sense for the DatabaseMonitor to send an IDataItem&lt;TableRow&gt; to a processor that assumed it was getting IDataItem&lt;FileInfo&gt;. Of course, there&#8217;s nothing stopping you from having an uber Process() method that looks to see what types it&#8217;s getting understand multiple item types. The Process method on the IDataProcessor interface is actually set to receive IDataItem [without a specific type] for just this reason and GetString will suffice it you&#8217;re only inspecting contents.</p>
<h3>Back to implementing IDataProcessor</h3>
<p>For the sake of simplicity, let&#8217;s simply inspect the name of the new files and return True if the file has one name, and False for any other file:</p>
<pre class="brush:csharp">public bool Process(IDataItem item)
{
    IDataItem&lt;FileInfo&gt; fileItem = (IDataItem&lt;FileInfo&gt;)item;

    if (fileItem.Data.Name == "success.csv")
    {
        return true;
    }
    else
    {
        return false;
    }
}</pre>
<p>First, we cast the item to an instance of IDataItem&lt;FileInfo&gt;. Next, we check the file name using the Name property of Data, which is a FileInfo object of course. If it is success.csv, return True. Otherwise, return False.</p>
<h2>Configuration</h2>
<p>Now that we our simple processor,  we need to configure a monitor in our app.config:</p>
<pre class="brush:xml">&lt;siphon&gt;
  &lt;monitors&gt;
    &lt;monitor name="CsvMonitor" type="ChrisLaco.Siphon.LocalDirectoryMonitor, Siphon"&gt;
      &lt;settings&gt;
        &lt;add name="Path" value="C:\" /&gt;
        &lt;add name="Filter" value="*.csv" /&gt;
        &lt;add name="ProcessCompleteActions" value="Rename, Move" /&gt;
        &lt;add name="ProcessFailureActions" value="Rename, Move" /&gt;
        &lt;add name="CompletePath" value="Completed" /&gt;
        &lt;add name="FailurePath" value="Failed" /&gt;
        &lt;add name="CreateMissingFolders" value="True" /&gt;
      &lt;/settings&gt;
      &lt;schedule type="ChrisLaco.Siphon.DailySchedule, Siphon"&gt;
        &lt;daily&gt;
          &lt;time value="8:00" /&gt;
          &lt;time value="15:00" /&gt;
        &lt;/daily&gt;
      &lt;/schedule&gt;
      &lt;processor type="CustomProcessor, CustomProcessor" /&gt;
    &lt;/monitor&gt;
  &lt;/monitors&gt;
&lt;/siphon&gt;</pre>
<p>First we give the monitor a name and tell Siphon what class to use:</p>
<pre class="brush:xml">&lt;monitor name="CsvMonitor" type="ChrisLaco.Siphon.LocalDirectoryMonitor, Siphon"&gt;</pre>
<p>Next, we need to configure the monitor using the settings group:</p>
<ul>
<li><strong>Path</strong>: The full path where to scan for new files.</li>
<li><strong>Filter</strong>: The file name filter to use; only returning files that match the filter.</li>
<li><strong>ProcessCompleteActions</strong>:<strong> </strong>The actions to perform on the files when processing is successful.</li>
<li><strong>ProcessFailureActions</strong>: The actions to perform on the files when processing fails.</li>
<li><strong>CompletePath</strong>: The relative or full path to the folder to move files into when processing succeeds if the Move action is set.</li>
<li><strong>FailurePath</strong>: The relative or full path to the folder to move files into when processing fails if the Move action is set.</li>
<li><strong>CreateMissingFolders</strong>: Create the Path, CompletePath and FailurePath folders if they do not already exist.</li>
</ul>
<p>In Siphon, whenever possible, the Path, FailurePath and CompletePath options accept and convert to use Uri objects internally. C:\ is converted to file:///C:/. This is because the same code is used for remote folders as well in FtpMonitor, where Path could be ftp://example.com/ instead. Just like internet uris, the CompletePath and FailurePath settings can be absolute (ftp://example.com/failure/), root relative (/failure/) or relative to the path directory (../failure). This allows you to easily nest directories if necessary.</p>
<p>Now that we have our monitor configured, we need to give it a schedule:</p>
<pre class="brush:xml">&lt;schedule type="ChrisLaco.Siphon.DailySchedule, Siphon"&gt;
  &lt;daily&gt;
    &lt;time value="8:00" /&gt;
    &lt;time value="15:00" /&gt;
  &lt;/daily&gt;
&lt;/schedule&gt;</pre>
<p>Here we&#8217;ve selected the DailySchedule class and set two times of day to schan for new files: 8:00 and 15:00. The times are in the local server time zone and based on 24 hour notation. The only thing left to do is send the data to our custom processor above:</p>
<pre class="brush:xml">&lt;processor type="CustomProcessor, CustomProcessor" /&gt;</pre>
<h2>Running Your Monitor</h2>
<p>We have a custom processor and a fresh config. Now we need to run it. There are two ways to make use of your monitors in Siphon:</p>
<ol>
<li><strong>SiphonService</strong>: Windows Service that loads monitors from app.config at startup and runs the monitors based on their schedules.</li>
<li><strong>SiphonConsole</strong>: Command line utility that loads monitors from app.config and runs the monitors manually.</li>
<li><strong>Both</strong>: Use the command line utility to run a monitor immediately that is hosted on a local/remote SiphonService.</li>
</ol>
<p>If you want to run your monitor automatically, simply add it to SiphonService.exe.config whever SiphonService is installed and restart the service. If you want to run your monitor manually fomr the command line, add it to SiphonConsole.exe.config.</p>
<p>The run a monitor, or all monitors from the command line, simple do:</p>
<pre class="brush:xml">C:\Siphon&gt;SiphonConsole.exe CsvMonitor
C:\Siphon&gt;SiphonConsole.exe *</pre>
<p>To run a monitor hosted by SiphonService, simply supply the location of the service, then the monitor name:</p>
<pre class="brush:xml">C:\Siphon&gt;SiphonConsole.exe http://localhost/ServiceAdminPath CsvMonitor
C:\Siphon&gt;SiphonConsole.exe http://myotherserver/ServiceAdminPath *</pre>
<p>If you want to run monitors on hosted under SiphonService, you must enable the remote administration in the config:</p>
<pre class="brush:xml">&lt;siphon enableRemoteAdministration="True"&gt;</pre>
<p>We&#8217;ll cover how to control the administration url/port from config as wel as using endpoint configurations instead of the http url i the console in a future post. Happy monitoring!</p>
]]></content:encoded>
			<wfw:commentRss>http://chrislaco.com/articles/monitoring-local-directories-with-siphon/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Siphon Configuration</title>
		<link>http://chrislaco.com/articles/siphon-configuration/</link>
		<comments>http://chrislaco.com/articles/siphon-configuration/#comments</comments>
		<pubDate>Mon, 16 Mar 2009 02:53:49 +0000</pubDate>
		<dc:creator>claco</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[configuration]]></category>
		<category><![CDATA[siphon]]></category>

		<guid isPermaLink="false">http://chrislaco.com/?p=166</guid>
		<description><![CDATA[This is the second in a series of posts about Siphon, a set of data monitoring utilities for .NET under the MIT license. The source code can be found on GitHub. Introduction In this article, I&#8217;m going to cover how &#8230; <a href="http://chrislaco.com/articles/siphon-configuration/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>This is the second in a series of posts about Siphon, a set of data monitoring utilities for .NET under the MIT license. The source code can be found on <a title="Siphon on GitHub" href="http://github.com/claco/siphon/">GitHub</a>.</p>
<h2><span id="more-166"></span>Introduction</h2>
<p>In this article, I&#8217;m going to cover how Siphon configuration works, the options and how to use the configuration classes to read/write configuration information.</p>
<h2>Configuration Section</h2>
<p>Here&#8217;s a sample Siphon configuration section from the source code:</p>
<pre class="brush:xml">&lt;configSections&gt;
  &lt;section name="siphon" type="ChrisLaco.Siphon.SiphonConfigurationSection, Siphon" /&gt;
&lt;/configSections&gt;

&lt;siphon&gt;
  &lt;monitors&gt;
    &lt;monitor name="IntervalMonitor" type="ChrisLaco.Siphon.LocalDirectoryMonitor, Siphon"&gt;
      &lt;settings&gt;
        &lt;add name="Path" value="C:\" /&gt;
        &lt;add name="Filter" value="*.tmp" /&gt;
      &lt;/settings&gt;
      &lt;schedule type="ChrisLaco.Siphon.IntervalSchedule, Siphon"&gt;
        &lt;interval value="1.2:3:4" /&gt;
      &lt;/schedule&gt;
      &lt;processor type="ChrisLaco.Siphon.DummyProcessor, Siphon" /&gt;
    &lt;/monitor&gt;
  &lt;/monitors&gt;
&lt;/siphon&gt;</pre>
<p>Let&#8217;s break this down piece by piece. First, we need to tell .NET who&#8217;s in charge of the siphon configuration section:</p>
<pre class="brush:xml">&lt;configSections&gt;
 &lt;section name="siphon" type="ChrisLaco.Siphon.SiphonConfigurationSection, Siphon" /&gt;
&lt;/configSections&gt;</pre>
<p>Next, we add a new monitor element to the monitors collection:</p>
<pre class="brush:xml">&lt;monitor name="IntervalMonitor" type="ChrisLaco.Siphon.LocalDirectoryMonitor, Siphon"&gt;</pre>
<p>Here we have a monitor named IntervalMonitor and told Siphon what type to load. If you&#8217;re not familiar with using type strings in .NET configuration,  the string above tells .NET that we want to use the class ChrisLaco.Siphon.LocalDirectoryMonitor in the Siphon assembly. Note that if you want to use types that are installed into the GAC you will need to use the full type string including the Culture, PublicKeyToken and Version.</p>
<p>Next, we configure setting required by the LocalDirectoryMonitor:</p>
<pre class="brush:xml">&lt;settings&gt;
  &lt;add name="Path" value="C:\" /&gt;
  &lt;add name="Filter" value="*.tmp" /&gt;
&lt;/settings&gt;</pre>
<p>The settings consist of name/value pairs that are passed to the monitors Initialize() method. The number of options and their values vary depending on the monitor being used. Next, we&#8217;ll tell the monitor how often to look for new data:</p>
<pre class="brush:xml">&lt;schedule type="ChrisLaco.Siphon.IntervalSchedule, Siphon"&gt;
  &lt;interval value="1.2:3:4" /&gt;
&lt;/schedule&gt;</pre>
<p>Just like with the monitor element above, we need to tell Siphon what schedule class we want to use. In our case, we&#8217;re going to use the IntervalSchedule, and set the interval using a string TimeSpan.Parse() understands: 1 day, 2 hours, 3 minutes and 4 seconds. If you are interested in a daily schedule, you can also use the daily element to specify a daily schedule:</p>
<pre class="brush:xml">&lt;schedule type="ChrisLaco.Siphon.DailySchedule, Siphon"&gt;
  &lt;daily&gt;
    &lt;time value="8:00" /&gt;
    &lt;time value="15:00" /&gt;
  &lt;/daily&gt;
&lt;/schedule&gt;</pre>
<p>Note: whether you use an interval or a daily schedule, the schedule type you use must understand the configuration you&#8217;ve chosen. As we&#8217;ll see in the Configuration classes later, the configuration format is setup to handle the most common use cases, like daily schedule values. Just like the monitor element, the schedule element also has a settings element used to pass name/value options to the specified schedule type.</p>
<p>Now that we&#8217;ve chosen a monitor and a schedule, the last thing to do is to tell Siphon who will process the newly found data as it arrives:</p>
<pre class="brush:xml">&lt;processor type="ChrisLaco.Siphon.DummyProcessor, Siphon" /&gt;</pre>
<p>Here we&#8217;ve loaded the DummyProcessor, which does does nothing with new data and always returns True. As with the monitor and schedule elements, the processor element also has a settings element collection.</p>
<h2>Reading Configuration</h2>
<p>Siphon comes with a set of classes to read/write siphon configuration data. Once you have finished setting up your app.config, you can use the SiphonConfigurationSection class to load the section and loop through all of the configured monitors:</p>
<pre class="brush:vb">REM Load config section: defaults to 'siphon'
Dim section As SiphonConfigurationSection = SiphonConfigurationSection.GetSection

REM Loop through monitor elements
For Each monitor As MonitorElement In section.Monitors

    REM Get a setting
    Dim path As String = monitor.Settings("Path").Value

    REM create an instance of the specified type
    Dim instance As IDataMonitor = monitor.CreateInstance
    instance.Path = path

    REM Set the schedule
    instance.Schedule = monitor.Schedule.CreateInstance

    REM Set the processor
    instance.Processor = monitor.Processor.CreateInstance

    REM Process new data
    instance.Process()
Next</pre>
<p>The code above is pretty straight forward. One item of interest: when CreateInstance is called, it creates an instance of the specified type and calls the Initialize() method on the new instance. While we set the Path setting manually, the monitors Initialize() could have also done the same thing.</p>
<p>All monitors must implement the IDataMonitor interface. All schedules must implement the IMonitorSchedule interface and all processors must implement the IDataProcessor interface. CreateInstance() looks for a constructor with no parameters in the type being created.</p>
<h2>Writing Configuration</h2>
<p>You can also use the configuration classes to programaticaly create configuration files. SImply create the settings in code, then save the config to the specified file:</p>
<pre class="brush:vb">Dim config As Configuration = ConfigurationManager.OpenExeConfiguration("C:\Path\To\SomeApp.exe")
Dim section As New SiphonConfigurationSection
Dim monitor As New MonitorElement("TestMonitor", "LocalDirectoryMonitor, Siphon")

monitor.Settings.Add(New NameValueConfigurationElement("Path", "C:\"))
monitor.Processor = New ProcessorElement("MockProcessor, SiphonTests")
monitor.Processor.Settings.Add(New NameValueConfigurationElement("Foo", "Bar"))
monitor.Schedule.Type = "IntervalSchedule, Siphon"
monitor.Schedule.Daily.Add(New TimeElement(New TimeSpan(100)))
monitor.Schedule.Daily.Add(New TimeSpan(200))
section.Monitors.Add(monitor)

config.Sections.Add("siphon", section)
config.Save()</pre>
<p>This will update the app.config file for the specified executable path with the new configuration information. The code above will generate something like this:</p>
<pre class="brush:vb">&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;configuration&gt;
    &lt;configSections&gt;
        &lt;section name="siphon" type="ChrisLaco.Siphon.SiphonConfigurationSection, Siphon, Version=1.0.0.0, Culture=neutral, PublicKeyToken=0576062738dd7ad9" /&gt;
    &lt;/configSections&gt;
    &lt;siphon&gt;
        &lt;monitors&gt;
            &lt;monitor name="TestMonitor" type="LocalDirectoryMonitor, Siphon"&gt;
                &lt;schedule type="IntervalSchedule, Siphon"&gt;
                    &lt;interval value="00:01:00" /&gt;
                    &lt;daily&gt;
                        &lt;time value="00:00:00.0000100" /&gt;
                        &lt;time value="00:00:00.0000200" /&gt;
                    &lt;/daily&gt;
                &lt;/schedule&gt;
                &lt;processor type="MockProcessor, SiphonTests"&gt;
                    &lt;settings&gt;
                        &lt;add name="Foo" value="Bar" /&gt;
                    &lt;/settings&gt;
                &lt;/processor&gt;
                &lt;settings&gt;
                    &lt;add name="Path" value="C:\" /&gt;
                &lt;/settings&gt;
            &lt;/monitor&gt;
        &lt;/monitors&gt;
    &lt;/siphon&gt;
&lt;/configuration&gt;</pre>
]]></content:encoded>
			<wfw:commentRss>http://chrislaco.com/articles/siphon-configuration/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>An Introduction To Siphon</title>
		<link>http://chrislaco.com/articles/an-introduction-to-siphon/</link>
		<comments>http://chrislaco.com/articles/an-introduction-to-siphon/#comments</comments>
		<pubDate>Sun, 15 Mar 2009 17:27:00 +0000</pubDate>
		<dc:creator>claco</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[console]]></category>
		<category><![CDATA[ftp]]></category>
		<category><![CDATA[imap]]></category>
		<category><![CDATA[msmq]]></category>
		<category><![CDATA[pop3]]></category>
		<category><![CDATA[service]]></category>
		<category><![CDATA[siphon]]></category>

		<guid isPermaLink="false">http://chrislaco.com/?p=157</guid>
		<description><![CDATA[This is the first in a series of posts about Siphon, a set of data monitoring utilities for .NET under the MIT license. The source code can be found on GitHub. Introduction For me, writing software seems to be about &#8230; <a href="http://chrislaco.com/articles/an-introduction-to-siphon/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>This is the first in a series of posts about Siphon, a set of data monitoring utilities for .NET under the MIT license. The source code can be found on <a title="Siphon on GitHub" href="http://github.com/claco/siphon/">GitHub</a>.</p>
<h2><span id="more-157"></span>Introduction</h2>
<p>For me, writing software seems to be about scratching an itch, filling a need by creating your own solution. Siphon is such a project. It seems that almost every project that come across my desk has the need to monitor some directory for files to process. Sometimes that&#8217;s a local directory. Sometimes that&#8217;s a remote ftp directory. Sometimes it&#8217;s even a pop3 mailbox. After watching numerous similar scheduled tasks, batch files, vbscript and command line utilities  being created I decided to create Siphon to help get all of these tasks back into more consistent manageable pieces.</p>
<p>Siphon is a set of tools to allow you to monitor data on a specific schedule and send that data off or processing. There are three basic parts used to accomplish this:</p>
<ol>
<li>Data Monitors: What do you want to monitor?</li>
<li>Monitor Schedules: When do you want to check for new data?</li>
<li>Data Processors: What do you want to do with the new data?</li>
</ol>
<p>These three parts are combined in code or in config files to accomplish the task of monitors and processing new data. These tasks can be configured and run manually using SiphonConsole, and command line utilities for running local/remote monitoring jobs, or SiphonService, a Windows Service that runs jobs based on the schedules supplied.</p>
<h2>Data Monitors</h2>
<p>The following data monitors are currently supported:</p>
<ul>
<li>LocalDirectoryMonitor: Monitor local file system directories for new files.</li>
<li>FtpDirectoryMonitor: Monitor remote ftp directories for new files.</li>
<li>ImapMonitor: Monitor IMAP mail boxes for new messages.</li>
<li>Pop3Monitor: Monitor POP3 mail boxes for new messages.</li>
<li>MessageQueueMonitor: Monitor MSMQ queues for new messages.</li>
<li>DatabaseMonitor: Monitor any DbProviderFactory support database for new records.</li>
</ul>
<p>Data monitors can take separate sets of actions against the data when processing complete/fails. These actions include:</p>
<ul>
<li>Delete: Delete the data when processing completes/fails.</li>
<li>Move:  Move the data when processing completes/fails.</li>
<li>Rename: Rename the data when processing completes/fails.</li>
<li>Update: Update the data when processing completes/fails.</li>
<li>Combined: combine any of these actions together, i.e. Rename then Move.</li>
</ul>
<h2>Monitor Schedules</h2>
<p>The following monitor schedules are currently supported:</p>
<ul>
<li>IntervalSchedule: Run whenever a specified amount of time as passed.</li>
<li>DailySchedule: Run at the same time(s) every day.</li>
</ul>
<h2>Requirements</h2>
<p>In order to run Siphon you must have the following:</p>
<ul>
<li>.NET 3.5</li>
<li>log4Net for logging (Free)</li>
<li>Lumisoft.NET for FTP/IMAP/POP3 protocol support (Free)</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://chrislaco.com/articles/an-introduction-to-siphon/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
