<?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 &#187; siphon</title>
	<atom:link href="http://chrislaco.com/tag/siphon/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>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>
