<?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/"
	xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule"
>

<channel>
	<title>A mind less ordinary &#187; Coding</title>
	<atom:link href="http://www.dmi.me.uk/blog/category/coding/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.dmi.me.uk/blog</link>
	<description></description>
	<lastBuildDate>Wed, 18 Aug 2010 13:17:48 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
<creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/3.0/</creativeCommons:license>
		<item>
		<title>Gracefully degrading jQuery edit-in-place</title>
		<link>http://www.dmi.me.uk/blog/2010/02/03/gracefully-degrading-jquery-edit-in-place/</link>
		<comments>http://www.dmi.me.uk/blog/2010/02/03/gracefully-degrading-jquery-edit-in-place/#comments</comments>
		<pubDate>Wed, 03 Feb 2010 22:34:49 +0000</pubDate>
		<dc:creator>Dave</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[code snippet]]></category>
		<category><![CDATA[plugin]]></category>

		<guid isPermaLink="false">http://www.dmi.me.uk/blog/?p=215</guid>
		<description><![CDATA[<p>I recently became curious about creating some edit-in-place controls: things that look like static text until you click them, and they magically become editable. It turns out that creating this sort of thing is almost trivial with jQuery, which is now my favourite JavaScript framework. I&#8217;m a big fan of functional-style programming, and jQuery plays right <a href="http://www.dmi.me.uk/blog/2010/02/03/gracefully-degrading-jquery-edit-in-place/">[...]</a>]]></description>
			<content:encoded><![CDATA[<p>I recently became curious about creating some edit-in-place controls: things that look like static text until you click them, and they magically become editable. It turns out that creating this sort of thing is almost trivial with <a title="jQuery home page" href="http://jquery.com/" target="_blank">jQuery</a>, which is now my favourite JavaScript framework. I&#8217;m a big fan of functional-style programming, and jQuery plays right into that.</p>
<p>It was still surprising that the bulk of what I wanted to do can be done in about 16 lines of code. That&#8217;s right: sixteen.</p>
<p>The plan was to create an edit-in-place system that would degrade nicely in browsers with JavaScript disabled. This isn&#8217;t necessarily as elegant as it could be and it doesn&#8217;t yet handle all input types, but that&#8217;s what version one is for! So without further ado, I present the code:</p>
<pre>
<div class="codecolorer-container javascript twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$.<span style="color: #660066;">fn</span>.<span style="color: #660066;">in_place_edit</span> <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">each</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> $eip <span style="color: #339933;">=</span> $<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'&lt;span&gt;&lt;/span&gt;'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> $el<span style="color: #339933;">=</span>$<span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">this</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">hide</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">after</span><span style="color: #009900;">&#40;</span>$eip<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; $eip.<span style="color: #660066;">text</span><span style="color: #009900;">&#40;</span>$el.<span style="color: #660066;">val</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; $eip.<span style="color: #660066;">click</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span> $eip.<span style="color: #660066;">hide</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> $el.<span style="color: #660066;">data</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'origval'</span><span style="color: #339933;">,</span> $el.<span style="color: #660066;">val</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">show</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #000066;">focus</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">select</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; $el.<span style="color: #000066;">blur</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span>$el.<span style="color: #000066; font-weight: bold;">is</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'select'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> $el.<span style="color: #660066;">data</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'origval'</span><span style="color: #339933;">,</span> $el.<span style="color: #660066;">val</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; $eip.<span style="color: #660066;">text</span><span style="color: #009900;">&#40;</span>$el.<span style="color: #660066;">data</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'origval'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">show</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> $el.<span style="color: #660066;">hide</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">val</span><span style="color: #009900;">&#40;</span>$el.<span style="color: #660066;">data</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'origval'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; $el.<span style="color: #660066;">keydown</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>e<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>e.<span style="color: #660066;">which</span><span style="color: #339933;">==</span><span style="color: #CC0000;">27</span><span style="color: #009900;">&#41;</span> $el.<span style="color: #660066;">val</span><span style="color: #009900;">&#40;</span>$el.<span style="color: #660066;">data</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'origval'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>.<span style="color: #000066;">blur</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>e.<span style="color: #660066;">which</span><span style="color: #339933;">==</span><span style="color: #CC0000;">13</span><span style="color: #339933;">||</span>e.<span style="color: #660066;">which</span><span style="color: #339933;">==</span><span style="color: #CC0000;">9</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; e.<span style="color: #660066;">preventDefault</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; $el.<span style="color: #660066;">data</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'origval'</span><span style="color: #339933;">,</span> $el.<span style="color: #660066;">val</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>.<span style="color: #000066;">blur</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span></div></div>
</pre>
<p>Usage:</p>
<pre>
<div class="codecolorer-container javascript twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$<span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span> $<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'input, select'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">in_place_edit</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
</pre>
<p>So, what does all this do? First of all, we create a new function on the main jQuery object, called <code class="codecolorer text default"><span class="text">in_place_edit</span></code>. This then iterates over elements matching the selector. It hides the input and creates a placeholder <code class="codecolorer html4strict default"><span class="html4strict"><span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">span</span>&gt;</span></span></code> element with the input&#8217;s value. Then we simply set up event handlers to deal with the placeholder being clicked, the input losing focus, and various keypresses (enter/tab to accept, esc to cancel). To see it in action, I&#8217;ve put together a rough-and-ready <a href="http://test.dmi.me.uk/in-place-test.html">demo</a>.</p>
<p>Planned future enhancements:</p>
<ul>
<li>Checkbox input types (display using the labels?)</li>
<li>Radio input types</li>
<li>File input types (if possible)</li>
<li>Textareas</li>
<li>Any other types&#8230;</li>
</ul>
<p>Maybe further updates later on!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dmi.me.uk/blog/2010/02/03/gracefully-degrading-jquery-edit-in-place/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/3.0/</creativeCommons:license>
	</item>
		<item>
		<title>A content-based file manager</title>
		<link>http://www.dmi.me.uk/blog/2009/06/04/a-content-based-file-manager/</link>
		<comments>http://www.dmi.me.uk/blog/2009/06/04/a-content-based-file-manager/#comments</comments>
		<pubDate>Thu, 04 Jun 2009 22:12:38 +0000</pubDate>
		<dc:creator>Dave</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[Insight (semantic filesystem)]]></category>
		<category><![CDATA[Projects]]></category>
		<category><![CDATA[Braindump]]></category>
		<category><![CDATA[file manager]]></category>
		<category><![CDATA[ideas]]></category>

		<guid isPermaLink="false">http://www.dmi.me.uk/blog/?p=124</guid>
		<description><![CDATA[<p>I&#8217;ve been thinking recently about Insight again, and I&#8217;ve been considering part of the problem with naming and uniqueness.</p>
<p>Names in a traditional file system are made unique based on a full path to the file, but most people think of a file name as just the final component. This would then cause a problem with the <a href="http://www.dmi.me.uk/blog/2009/06/04/a-content-based-file-manager/">[...]</a>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been thinking recently about Insight again, and I&#8217;ve been considering part of the problem with naming and uniqueness.</p>
<p>Names in a traditional file system are made unique based on a full path to the file, but most people think of a file name as just the final component. This would then cause a problem with the move to Insight, as a file could appear in multiple directories, and its only distinguishing feature would be the final component of its path. This is counter-intuitive and can cause all sorts of problems.</p>
<p>Consider makefiles, for example. They rely on a standard named file (<tt>Makefile</tt>) appearing at various levels in the hierarchy in order to work. Obviously, you would want different makefiles at different levels and in different projects, but Insight as it stands has no way to handle this.</p>
<p>I then started thinking about what makes a file unique. In the end, I came up with two things: name and content. This covers the makefile case (same name, different content) as well as the backup case (same content, different name). It then occurred to me that, in the general case, all you need to distinguish a file is its content, and then actually finding it can all be left up to metadata.</p>
<p><span id="more-124"></span>If files are then thought of as containers for data that happen to have a unique internal identifier (which never needs to be exposed to the user, although it can be accessed as, say, the file&#8217;s inode number) then the idea of a content-based file manager comes into play. These examples work best with visual media, particularly images, but there is no reason in principle that this could not be extended.</p>
<p>Imagine searching for a file. You know it&#8217;s a photo, but you have a large collection of them. With a digital camera and a large-capacity memory card, who needs to ever delete a photo? We&#8217;ll assume that you&#8217;ve dilligently tagged the photos with metadata as you&#8217;ve imported them from the camera, through some easy batch process.</p>
<p>On the tagging point: a lot can be taken from the metadata stored by the camera (date/time, resolution, orientation, black and white/colour, perhaps GPS co-ordinates) and with the right tools, more can be inferred (auto-tagging faces, buildings, perhaps recognising common events like football matches, converting GPS co-ordinates to places, &#8230;). As time goes on, people will need to do less and less manual tagging.</p>
<p>Anyway, back to the file manager. You know you are after a picture or a set of pictures. Normal thought processes will probably follow a path similar to: &#8220;Yeah, I wanted to show dad those <strong>photos</strong> from that <strong>holiday</strong> in <strong>Paris</strong> that we had <strong>two months ago</strong>. I think he&#8217;d particularly like the ones we got of the <strong>Louvre</strong>, as well as the ones <strong>with me in</strong>, of course.&#8221; I&#8217;ve highlighted various key words that can be translated directly to metadata searches. Notice how these all involve a narrowing down of the query.</p>
<p>To convert these to filters, we then have:</p>
<ul>
<li>type: <strong>photo</strong></li>
<li><strong>holiday</strong></li>
<li>location: <strong>Paris</strong></li>
<li>date: <strong>two months ago</strong></li>
<li>at least one of:
<ul>
<li>location: <strong>Louvre</strong></li>
<li>person: <strong>Me</strong></li>
</ul>
</li>
</ul>
<p>This could also be represented by a query:</p>
<blockquote>
<div class="codecolorer-container text twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">type:photo AND holiday AND location:Paris AND date:-2m<br />
AND (location:Louvre OR person:me)</div></div>
</blockquote>
<p>Breaking it down in this way feels fairly technical and wordy, however. I&#8217;d much prefer a visual view.</p>
<p>Imagine a black field, speckled with points of light representing your photos:</p>
<p><img class="aligncenter size-full wp-image-131" title="Content File Manager 1" src="http://www.dmi.me.uk/blog/wp-content/uploads/2009/06/content-file-manager-1.png" alt="Content File Manager 1" width="450" height="340" /></p>
<p>You filter by &#8220;holiday&#8221;, and (because it learns based on previous searches) it then groups by location. The ones which have been filtered out fade into nothing, and the photos group into labelled blobs and enlarge slightly:</p>
<p><img class="aligncenter size-full wp-image-132" title="Content File Manager 2" src="http://www.dmi.me.uk/blog/wp-content/uploads/2009/06/content-file-manager-2.png" alt="Content File Manager 2" width="450" height="340" /></p>
<p>You filter by date, and as you drag the slider, irrelevant items fade away and relevant ones enlarge:</p>
<p><img class="aligncenter size-full wp-image-133" title="Content File Manager 3" src="http://www.dmi.me.uk/blog/wp-content/uploads/2009/06/content-file-manager-3.png" alt="Content File Manager 3" width="450" height="340" /></p>
<p>Then you add the final filters and set the photos up for viewing, perhaps as a slideshow&#8230; and you&#8217;re done!</p>
<p>Pretty neat, I think.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dmi.me.uk/blog/2009/06/04/a-content-based-file-manager/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/3.0/</creativeCommons:license>
	</item>
		<item>
		<title>mod_sqltemplate: A distraction from work</title>
		<link>http://www.dmi.me.uk/blog/2008/09/10/mod_sqltemplate-a-distraction-from-work/</link>
		<comments>http://www.dmi.me.uk/blog/2008/09/10/mod_sqltemplate-a-distraction-from-work/#comments</comments>
		<pubDate>Wed, 10 Sep 2008 20:48:37 +0000</pubDate>
		<dc:creator>Dave</dc:creator>
				<category><![CDATA[mod_sqltemplate]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[APR]]></category>
		<category><![CDATA[DBD]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://www.dmi.me.uk/blog/?p=86</guid>
		<description><![CDATA[<p>I&#8217;ve begun the long and (hopefully) interesting task of working on mod_sqltemplate.  I have not yet found a tutorial or guide to working with APR&#8217;s DBD API (the database abstraction layer for the Apache Portable Runtime), so I&#8217;ll write one and publish it here as I <a href="http://www.dmi.me.uk/blog/2008/09/10/mod_sqltemplate-a-distraction-from-work/">[...]</a>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve begun the long and (hopefully) interesting task of working on mod_sqltemplate.  I have not yet found a tutorial or guide to working with APR&#8217;s DBD API (the database abstraction layer for the Apache Portable Runtime), so I&#8217;ll write one and publish it here as I go along&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dmi.me.uk/blog/2008/09/10/mod_sqltemplate-a-distraction-from-work/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/3.0/</creativeCommons:license>
	</item>
		<item>
		<title>Modules for Apache and PHP</title>
		<link>http://www.dmi.me.uk/blog/2008/08/13/modules-for-apache-and-php/</link>
		<comments>http://www.dmi.me.uk/blog/2008/08/13/modules-for-apache-and-php/#comments</comments>
		<pubDate>Wed, 13 Aug 2008 20:26:54 +0000</pubDate>
		<dc:creator>Dave</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[extensions]]></category>
		<category><![CDATA[modules]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://www.dmi.me.uk/blog/?p=74</guid>
		<description><![CDATA[<p>The number of projects I have in mind just keeps growing&#8230; I really need to get something together to organise them, and remember them! But here are two more to add to the list: an Apache module for dynamic configuration generation and a PHP framework inside an extension. Read on for a monster post with more <a href="http://www.dmi.me.uk/blog/2008/08/13/modules-for-apache-and-php/">[...]</a>]]></description>
			<content:encoded><![CDATA[<p>The number of projects I have in mind just keeps growing&#8230; I really need to get something together to organise them, and remember them! But here are two more to add to the list: an Apache module for dynamic configuration generation and a PHP framework inside an extension. Read on for a monster post with more information&#8230;</p>
<p><span id="more-74"></span></p>
<h2>Apache module</h2>
<p>The first thing I have in mind is to create an Apache 2.2 module that uses the APR (Apache Portable Runtime) to make configuration file templating easy.</p>
<p>On my server, there are a lot of very similar Apache configuration files. At the moment, they are semi-automatically generated by running a Perl script that reads the configuration from a database and then creates the output files as required. This is all well and good, but changing anything requires running the Perl script, regenerating all of the configuration files, then prodding Apache to reload its configuration. There has to be a better way, especially one that doesn&#8217;t require elevated permissions like that.</p>
<p>Enter my proposed solution: <tt>mod_sqltemplate</tt>. This module will add a few extra settings and (at least) two extra sections to the standard Apache configuration. The propsed features are:</p>
<ul>
<li><tt>SQLTemplate_DBDriver «driver»</tt> – sets the APR driver to be used</li>
<li><tt>SQLTemplate_DBOpts «option-string»</tt> – options for the driver (e.g. database name, username, password&#8230;)</li>
<li><tt>SQLTemplate_Caching «on|off»</tt> – enable/disable configuration caching</li>
<li><tt>SQLTemplate_CacheDir «path»</tt> – directory in which to save cached configurations</li>
<li><tt>&lt;SQLRepeat «query»&gt;</tt> – new section, as described below</li>
<li><tt>&lt;SQLCatSet «sep» «query»&gt;</tt> – new section, as described below</li>
</ul>
<h3>SQLRepeat</h3>
<p>The <tt>SQLRepeat</tt> section is probably going to be the most-used new directive. It provides templating functionality similar to <a title="mod_macro by Fabien Coelho" href="http://cri.ensmp.fr/~coelho/mod_macro/" target="_blank"><tt>mod_macro</tt></a>, although the template variables are taken from the column names of the query rather than being explicitly specified. The section will then be repeated for each row of the resultset, substitutions occurring as required.</p>
<p>Perhaps an example would help:</p>
<pre lang="apache">&lt;SQLRepeat "SELECT id,hostname,domain FROM apache_hosts"&gt;
&lt;VirtualHost *:80&gt;
  DocumentRoot /var/www/${hostname}.${domain}
  ServerName ${hostname}.${domain}
  # ...
&lt;/VirtualHost&gt;
&lt;/SQLRepeat&gt;</pre>
<p>For this example, I&#8217;ve avoided the configuration directives for clarity, assuming they are specified elsewhere. Supposing the database table contains simply:</p>
<table border="0">
<tbody>
<tr>
<th>ID</th>
<th>hostname</th>
<th>domain</th>
</tr>
<tr>
<td>1</td>
<td>www</td>
<td>example.com</td>
</tr>
<tr>
<td>3</td>
<td>test</td>
<td>example.com</td>
</tr>
<tr>
<td>12</td>
<td>yourhost</td>
<td>somewhere.local</td>
</tr>
</tbody>
</table>
<p>Then this will expand to be equivalent to:</p>
<pre lang="apache">&lt;VirtualHost *:80&gt;
  DocumentRoot /var/www/www.example.com
  ServerName www.example.com
  # ...
&lt;/VirtualHost&gt;
&lt;VirtualHost *:80&gt;
  DocumentRoot /var/www/test.example.com
  ServerName test.example.com
  # ...
&lt;/VirtualHost&gt;
&lt;VirtualHost *:80&gt;
  DocumentRoot /var/www/yourhost.somewhere.local
  ServerName yourhost.somewhere.local
  # ...
&lt;/VirtualHost&gt;</pre>
<p>And so on. These sections can be nested, so if you wanted to store a list of aliases as well:</p>
<table border="0">
<tbody>
<tr>
<th>ID</th>
<th>hostid</th>
<th>alias</th>
<th>target</th>
</tr>
<tr>
<td>1</td>
<td>1</td>
<td>/icons</td>
<td>/var/www/_share/icons</td>
</tr>
<tr>
<td>2</td>
<td>1</td>
<td>/example</td>
<td>/var/www/_share/foo</td>
</tr>
<tr>
<td>5</td>
<td>12</td>
<td>/bar</td>
<td>/var/www/_share/foo</td>
</tr>
</tbody>
</table>
<p>You could use something like this:</p>
<pre lang="apache">&lt;SQLRepeat "SELECT id,hostname,domain FROM apache_hosts"&gt;
&lt;VirtualHost *:80&gt;
  DocumentRoot /var/www/${hostname}.${domain}
  ServerName ${hostname}.${domain}
  # ...
  &lt;SQLRepeat "SELECT alias,target FROM apache_aliases WHERE hostid=?" ${id}&gt;
    Alias "${alias}" "${target}"
  &lt;/SQLRepeat&gt;
&lt;/VirtualHost&gt;
&lt;/SQLRepeat&gt;</pre>
<p>which would then expand to:</p>
<pre lang="apache">&lt;VirtualHost *:80&gt;
  DocumentRoot /var/www/www.example.com
  ServerName www.example.com
  # ...
    Alias "/icons" "/var/www/_share/icons"
    Alias "/example" "/var/www/_share/foo"
&lt;/VirtualHost&gt;
&lt;VirtualHost *:80&gt;
  DocumentRoot /var/www/test.example.com
  ServerName test.example.com
  # ...
&lt;/VirtualHost&gt;
&lt;VirtualHost *:80&gt;
  DocumentRoot /var/www/yourhost.somewhere.local
  ServerName yourhost.somewhere.local
  # ...
    Alias "/bar" "/var/www/_share/foo"
&lt;/VirtualHost&gt;</pre>
<p>So far, so good. Something to note is that the variable names above did not conflict. If we had included &#8220;id&#8221; in the list of columns for the inner <tt>SQLRepeat</tt>, then included <tt>${id}</tt>, the module should use the innermost scope. Disambiguation should be obtained by table alias prefixing (e.g. <tt>${apache_hosts.id}</tt> or <tt>${apache_aliases.id}</tt>). Full variable names should always be specified for clarity. This also shows that if the query returns no results, the repeating section is not included, as you would expect. Also note that queries that use variable substitution should use the prepared statement format, with variables specified afterwards. Variables will be included directly, so anything that might contain spaces must be quoted.</p>
<p>However, there are some directives like <tt>ServerAlias</tt> that must be specified once with a list of space-separated values. Enter <tt>SQLCatSet</tt>&#8230;</p>
<h3>SQLCatSet</h3>
<p>This acts in a similar way to <tt>SQLRepeat</tt>, but it concatenates all of the results for each field before substituting, and it includes its content at most once. If there are no results for the query, then it will not include its content. For example, with a server aliases table like:</p>
<table border="0">
<tbody>
<tr>
<th>ID</th>
<th>hostid</th>
<th>alias</th>
</tr>
<tr>
<td>1</td>
<td>3</td>
<td>test2.example.com</td>
</tr>
<tr>
<td>2</td>
<td>3</td>
<td>test.example.net</td>
</tr>
<tr>
<td>5</td>
<td>12</td>
<td>*.somewhere.local</td>
</tr>
</tbody>
</table>
<p>You could use something like this:</p>
<pre lang="apache">&lt;SQLRepeat "SELECT id,hostname,domain FROM apache_hosts"&gt;
&lt;VirtualHost *:80&gt;
  DocumentRoot /var/www/${hostname}.${domain}
  ServerName ${hostname}.${domain}
  &lt;SQLCatSet " " "SELECT alias FROM apache_server_aliases WHERE hostid=?" ${id}&gt;
    ServerAlias ${alias}
  &lt;/SQLCatSet&gt;
  # ...
  &lt;SQLRepeat "SELECT alias,target FROM apache_aliases WHERE hostid=?" ${id}&gt;
    Alias "${alias}" "${target}"
  &lt;/SQLRepeat&gt;
&lt;/VirtualHost&gt;
&lt;/SQLRepeat&gt;</pre>
<p>which would then expand to:</p>
<pre lang="apache">&lt;VirtualHost *:80&gt;
  DocumentRoot /var/www/www.example.com
  ServerName www.example.com
  # ...
    Alias "/icons" "/var/www/_share/icons"
    Alias "/example" "/var/www/_share/foo"
&lt;/VirtualHost&gt;
&lt;VirtualHost *:80&gt;
  DocumentRoot /var/www/test.example.com
  ServerName test.example.com
    ServerAlias test2.example.com test.example.net
  # ...
&lt;/VirtualHost&gt;
&lt;VirtualHost *:80&gt;
  DocumentRoot /var/www/yourhost.somewhere.local
  ServerName yourhost.somewhere.local
    ServerAlias *.somewhere.local
  # ...
    Alias "/bar" "/var/www/_share/foo"
&lt;/VirtualHost&gt;</pre>
<p>This would seem to cover the major functionality needed for automatically generating configurations in a really flexible way, although I&#8217;m sure more will probably be needed at some point&#8230; like <tt>SQLIf</tt>, perhaps.</p>
<h2>PHP Framework</h2>
<p>It occurs to me that having a framework&#8217;s code in PHP itself could mean that it is quite slow. It would be interesting to put together a framework in C and embedded as a module, to see if there are any memory/speed improvements possible. It might just be a case of implementing an ORM (Object Relational Model) system to begin with. Obviously, this idea is nowhere near as fully-formed!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dmi.me.uk/blog/2008/08/13/modules-for-apache-and-php/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/3.0/</creativeCommons:license>
	</item>
		<item>
		<title>In-place array uniq in C</title>
		<link>http://www.dmi.me.uk/blog/2008/07/10/in-place-uniq-in-c/</link>
		<comments>http://www.dmi.me.uk/blog/2008/07/10/in-place-uniq-in-c/#comments</comments>
		<pubDate>Thu, 10 Jul 2008 21:43:55 +0000</pubDate>
		<dc:creator>Dave</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[Facebook]]></category>
		<category><![CDATA[Hacks]]></category>
		<category><![CDATA[Insight (semantic filesystem)]]></category>
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.dmi.me.uk/blog/?p=64</guid>
		<description><![CDATA[<p>I&#8217;ve been developing Insight even though the uni project has come to an end, because it&#8217;s fun! I also want to make it more stable and eventually release it under an open-source licence of some kind. There will be an update coming soon, I promise! I now have Internet, so I can write up some things&#8230; <a href="http://www.dmi.me.uk/blog/2008/07/10/in-place-uniq-in-c/">[...]</a>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been developing <strong>Insight</strong> even though the uni project has come to an end, because it&#8217;s fun! I also want to make it more stable and eventually release it under an open-source licence of some kind. There will be an update coming soon, I promise! I now have Internet, so I can write up some things&#8230;  Anyway, one of the interesting things I wanted to do for Insight was an in-place form of <tt>uniq</tt> for an array, ideally without any additional memory allocation. It seems that this is something nobody else has done yet! So I set about doing it myself&#8230;  For those of you who are unfamiliar with the Linux/UNIX command <tt>uniq</tt>, it takes a sorted list and removes any duplicates. This is almost exactly what I&#8217;m trying to do, with one caveat: I need to keep the &#8220;discarded&#8221; duplicates.  What happens is that I have an array containing a number of strings, and these have all been dynamically allocated via <tt>malloc()</tt> or <tt>calloc()</tt>. If I just remove or overwrite their pointers, they&#8217;ll vanish and cause a memory leak. While I&#8217;ve now fixed a large number of leaks thanks to <a title="Valgrind debugger/profiler" href="http://valgrind.org" target="_blank">Valgrind</a>, I&#8217;m trying to actively avoid any possibility of adding them.  Read on for the details&#8230; <span id="more-64"></span></p>
<h2>The Idea</h2>
<p>The basic idea is that we have a sorted list of items that may have some duplicates, say:</p>
<pre>{A<sub>0</sub>, A<sub>1</sub>, B<sub>0</sub>, C<sub>0</sub>, C<sub>1</sub>, E<sub>0</sub>, F<sub>0</sub>, F<sub>1</sub>, F<sub>2</sub>, G<sub>0</sub>, H<sub>0</sub>, H<sub>1</sub>}</pre>
<p>and we want to remove all of the duplicates, so we get two sets:</p>
<pre>{A<sub>0</sub>, B<sub>0</sub>, C<sub>0</sub>, E<sub>0</sub>, F<sub>0</sub>, G<sub>0</sub>, H<sub>0</sub>} {A<sub>1</sub>, C<sub>1</sub>, F<sub>1</sub>, F<sub>2</sub>, H<sub>1</sub>}</pre>
<p>Note that it doesn&#8217;t matter which of the duplicates ends up in which set, just that the items in the first are all unique and that we don&#8217;t lose any. Also, <tt>A<sub>0</sub></tt> and <tt>A<sub>1</sub></tt> have the same value but the subscript will help to distinguish exactly which of the <tt>A</tt>s I&#8217;m talking about.  Now we have the problem, let&#8217;s look at some solutions.</p>
<h3>Lossless solution &#8211; additional lists</h3>
<p>So the first solution uses two temporary lists, <tt>unique</tt> and <tt>duplicate</tt>. We start with two pointers into the original list: <tt>p</tt> and <tt>q</tt>. We set <tt>p</tt> to point to the start of the list, and <tt>q</tt> to point to the element after <tt>p</tt>. We then copy the item <tt>p</tt> points at to our <tt>unique</tt> list. Then, while we still have more items to examine:</p>
<ul>
<li>If the items pointed to by <tt>p</tt> and <tt>q</tt> have the same value, then we copy the item <tt>q</tt> points at to the <tt>duplicate</tt> list and advance <tt>p</tt> and <tt>q</tt>.</li>
<li>If they are different, we copy the item at <tt>q</tt> to our <tt>unique</tt> list, and advance <tt>p</tt> and <tt>q</tt>.</li>
</ul>
<p>We keep doing this until we get to the end of the array, and then copy the <tt>unique</tt> list to the start of the array, the <tt>duplicate</tt> list after that (both overwriting the previous contents) and set the number of unique items to the length of the <tt>unique</tt></p>
<p>list.</p>
<h3>Lossy solution &#8211; one list</h3>
<p>We can do a similar thing in-place, although this will result in data loss. The essential idea is:</p>
<ul>
<li>We start in the same way: <tt>p</tt> pointing to the first element, and <tt>q</tt> to the second</li>
<li>While <tt>q</tt> has the same value as <tt>p</tt>, advance <tt>q</tt> along the list</li>
<li>When they are different, advance <tt>p</tt>, copy <tt>q</tt> to <tt>p</tt>, and advance <tt>q</tt></li>
<li>Once <tt>q</tt> goes past the end of the list, we&#8217;re done, and the offset of <tt>p</tt> is the number of unique items.</li>
</ul>
<p>Now this is quite simple, and only requires one pass through the list, but it results in the loss of information, which is unacceptable in this case.</p>
<h3>Lossless solution &#8211; one list</h3>
<p>For this solution, we can also do it with one pass through the list and two pointers.  The basic intuition is that we&#8217;re going through the array, accumulating a rotating block of stuff that we don&#8217;t want. At any given point:</p>
<ul>
<li>Everything between the start and <tt>p</tt> (not inclusive) is the unique list (so far)</li>
<li>Everything between <tt>p</tt> and <tt>q</tt> (not inclusive) is an unwanted duplicate</li>
<li>Everything between <tt>q</tt> (inclusive) and the end is yet to be processed.</li>
</ul>
<p>At the end, we return the number of unique items at the start of the list; everything above that is a duplicate.</p>
<h2>For integers</h2>
<p>Here is some pseudo-Java that performs my algorithm for a set of integers.</p>
<pre>
<div class="codecolorer-container c twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333;">int</span> set_uniq<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> set<span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #993333;">int</span> count <span style="color: #339933;">=</span> set.<span style="color: #202020;">length</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #993333;">int</span> tmp<span style="color: #339933;">,</span> p<span style="color: #339933;">=</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> q<span style="color: #339933;">=</span><span style="color: #0000dd;">1</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span>p <span style="color: #339933;">&lt;</span> set.<span style="color: #202020;">length</span> <span style="color: #339933;">&amp;&amp;</span> q <span style="color: #339933;">&lt;</span> set.<span style="color: #202020;">length</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span>p <span style="color: #339933;">&lt;</span> set.<span style="color: #202020;">length</span> <span style="color: #339933;">&amp;&amp;</span> set<span style="color: #009900;">&#91;</span>p<span style="color: #009900;">&#93;</span> <span style="color: #339933;">!=</span> set<span style="color: #009900;">&#91;</span>q<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; p <span style="color: #339933;">=</span> p <span style="color: #339933;">+</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>q <span style="color: #339933;">&lt;</span> set.<span style="color: #202020;">length</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>p <span style="color: #339933;">&lt;</span> q<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tmp <span style="color: #339933;">=</span> set<span style="color: #009900;">&#91;</span>p<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; set<span style="color: #009900;">&#91;</span>p<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> set<span style="color: #009900;">&#91;</span>q<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; set<span style="color: #009900;">&#91;</span>q<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> tmp<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; q <span style="color: #339933;">=</span> q <span style="color: #339933;">+</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">else</span> <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>count <span style="color: #339933;">&gt;</span> p<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; count <span style="color: #339933;">=</span> p<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span>q <span style="color: #339933;">&lt;</span> max <span style="color: #339933;">&amp;&amp;</span> set<span style="color: #009900;">&#91;</span>p<span style="color: #009900;">&#93;</span> <span style="color: #339933;">==</span> set<span style="color: #009900;">&#91;</span>q<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; q <span style="color: #339933;">=</span> q <span style="color: #339933;">+</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; <span style="color: #666666; font-style: italic;">// q hit the end and is still the same as p</span><br />
&nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>count <span style="color: #339933;">&gt;</span> p<span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; count <span style="color: #339933;">=</span> p <span style="color: #339933;">+</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #b1b100;">return</span> count<span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
</pre>
<h2>The general code</h2>
<p>The arguments to the general <tt>set_uniq()</tt> function are very similar to the arguments to standard <tt>qsort()</tt>:</p>
<ul>
<li>The (sorted) array to work on</li>
<li>The number of items in the array</li>
<li>The size of each item in the array</li>
<li>A comparator function that returns a negative integer if the first argument is less than the second, zero if they are equal, and a positive integer if the first argument is greater than the second.</li>
</ul>
<p>So, without further ado, my code:</p>
<pre>
<div class="codecolorer-container c twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333;">int</span> set_uniq<span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span> <span style="color: #339933;">*</span>set<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; size_t count<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; size_t elem_size<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; <span style="color: #993333;">int</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">*</span>cmp<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">const</span> <span style="color: #993333;">void</span><span style="color: #339933;">*,</span> <span style="color: #993333;">const</span> <span style="color: #993333;">void</span><span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #993333;">void</span> <span style="color: #339933;">*</span>p<span style="color: #339933;">,</span> <span style="color: #339933;">*</span>q<span style="color: #339933;">,</span> <span style="color: #339933;">*</span>max<span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #993333;">void</span> <span style="color: #339933;">*</span>tmp<span style="color: #339933;">=</span>calloc<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> elem_size<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #808080; font-style: italic;">/* TODO: check for failure */</span><br />
&nbsp; p<span style="color: #339933;">=</span>set<span style="color: #339933;">;</span><br />
&nbsp; q<span style="color: #339933;">=</span>set<span style="color: #339933;">+</span>elem_size<span style="color: #339933;">;</span><br />
&nbsp; max<span style="color: #339933;">=</span>set<span style="color: #339933;">+</span><span style="color: #009900;">&#40;</span>count<span style="color: #339933;">*</span>elem_size<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span>p<span style="color: #339933;">&lt;</span> p<span style="color: #339933;">-</span>set<span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; count <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>p<span style="color: #339933;">-</span>set<span style="color: #009900;">&#41;</span><span style="color: #339933;">/</span>elem_size<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span>q p<span style="color: #339933;">-</span>set<span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; count <span style="color: #339933;">=</span> <span style="color: #0000dd;">1</span> <span style="color: #339933;">+</span> <span style="color: #009900;">&#40;</span>p<span style="color: #339933;">-</span>set<span style="color: #009900;">&#41;</span><span style="color: #339933;">/</span>elem_size<span style="color: #339933;">;</span><br />
&nbsp; ifree<span style="color: #009900;">&#40;</span>tmp<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #b1b100;">return</span> count<span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
</pre>
<h2>Conclusion</h2>
<p>This code is released under a Creative Commons licence (see below). A similar idea will work well for other solutions, like set difference. I&#8217;ll post those later if anyone really cares.  Also, there is a better way of swapping the items by using the fact that:</p>
<pre>
<div class="codecolorer-container c twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">a <span style="color: #339933;">^=</span> b<span style="color: #339933;">;</span><br />
b <span style="color: #339933;">^=</span> a<span style="color: #339933;">;</span><br />
a <span style="color: #339933;">^=</span> b<span style="color: #339933;">;</span></div></div>
</pre>
<p>swaps a and b without needing a temporary variable. If you just go along the data in 32-bit chunks, performing those XOR operations to swap the data. This actually works out to be 30% or so faster (if I remember correctly).  Finally &#8211; general code like this is always going to be slower than code that&#8217;s been specialised for a particular purpose. Calling this on integers, for example, will be much slower than coding an integer-specific version. I should also point out that you can just overwrite integers, as you don&#8217;t need to free them <img src='http://www.dmi.me.uk/blog/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' title="icon wink photo" /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.dmi.me.uk/blog/2008/07/10/in-place-uniq-in-c/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/3.0/</creativeCommons:license>
	</item>
		<item>
		<title>Overflowing with ideas</title>
		<link>http://www.dmi.me.uk/blog/2008/04/29/overflowing-with-ideas/</link>
		<comments>http://www.dmi.me.uk/blog/2008/04/29/overflowing-with-ideas/#comments</comments>
		<pubDate>Tue, 29 Apr 2008 16:44:07 +0000</pubDate>
		<dc:creator>Dave</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[OpenIntegrate]]></category>
		<category><![CDATA[PHP RAD system]]></category>
		<category><![CDATA[Partis]]></category>
		<category><![CDATA[Projects]]></category>
		<category><![CDATA[Braindump]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[ideas]]></category>
		<category><![CDATA[intercommunication]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[proposals]]></category>
		<category><![CDATA[RAD]]></category>
		<category><![CDATA[web integration]]></category>

		<guid isPermaLink="false">http://www.dmi.me.uk/blog/?p=50</guid>
		<description><![CDATA[<p>I&#8217;ve found myself overflowing with ideas as I try to focus on revision, so I thought I might as well scribble some of them down, if only to get them out of my head! To name the prominent few:</p>

More on Partis and its future
A web service integration API proposal
A PHP system to make it easy to <a href="http://www.dmi.me.uk/blog/2008/04/29/overflowing-with-ideas/">[...]</a>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve found myself overflowing with ideas as I try to focus on revision, so I thought I might as well scribble some of them down, if only to get them out of my head! To name the prominent few:</p>
<ul>
<li>More on Partis and its future</li>
<li>A web service integration API proposal</li>
<li>A PHP system to make it easy to plug together a load of code modules for rapid development</li>
<li>Not to mention some others which are too fleeting or too vague to pin down yet</li>
</ul>
<p><span id="more-50"></span></p>
<h2>Partis</h2>
<p><a title="Partis website" href="http://www.partis-project.net/" target="_blank">Partis</a> is the name of a project I had originally planned to put together many years ago when I started university (back in 2004!).</p>
<p>The basic idea was to create a P2P system that worked internally on networks using IP multicast for peer discovery, which also allowed browsing and cross-network searches. It would provide bandwidth limitations, both in terms of speed and amount, as well as dynamic limits (e.g. 500KB/s for the first 300MB downloaded, then 50KB/s thereafter).</p>
<p>While I think this is still a good idea for places like the halls networks (where we were limited to 5GB bandwidth per 24 hours) I have decided on a better direction for the project, which is something almost completely different: distributed backup.</p>
<p>I don&#8217;t want to talk about Partis too much in this post, as I want to discuss other things too, but I will note down some of my ideas and things that have come out of discussion with others.</p>
<p>Changing Partis to a distributed backup solution came from a fairly selfish beginning, as have many of my ideas. If I want to put a system together because I&#8217;ll find it very useful (and perhaps indispensible) then perhaps other people will think the same. When I was getting ready to begin my final year project, I wanted to be paranoid about my work. I wanted to guard against losing it in any conceivable way:</p>
<ul>
<li>Hard drive or computer dying or becoming corrupted or destroyed</li>
<li>Losing a USB stick</li>
<li>Accidental deletion/overwriting</li>
<li>Malicious tampering</li>
<li>Theft</li>
<li>External server failure (e.g. Department of Computing or my own server), although highly unlikely</li>
</ul>
<p>So after considering all these options, I thought it would be great to create a distributed P2P-style backup solution. Sadly I haven&#8217;t had the time to do this, but the basic idea for myself was to use the fact that many of the computers in the Department have an empty partition that is about 20GB in size. If I could use that space to store my data and redundantly distribute it across multiple machines (to account for failures/reformats/reinstalls, computer being off or in Windows or otherwise inaccessible, etc) then I would feel a bit safer. And of course I could use some spare space on my housemates&#8217; computers, and maybe my home computer, and my server, and some other friends around the country or even the world&#8230;</p>
<p>The data would have to be encrypted, of course, as I wouldn&#8217;t want just anyone reading it, and there would have to be checksums to guard against modification or corruption. I quickly realised that this project was something that I wouldn&#8217;t have the time to undertake in parallel to my Masters project, and that it might have made a viable alternative. Then of course, there&#8217;s the possibility of storing versioned copies of files, and the question of how to distribute everything, and so forth.</p>
<p>Then it hit me that other people would find this useful. Surely most students would want to have a gigabyte or more of redundant, safe storage? Then this creates and solves the problem of finding enough space at the same time. As a potential business model, for example, people could have 1GB of free storage by offering 3-5GB of their own disk for usage by the network.</p>
<p>There would be different storage tiers based on host reliability (uptime/online time/connection speed/etc) and so on. It would perhaps be possible to charge a premium for upper-tier storage (i.e. things you&#8217;d need to be able to recover ASAP) as opposed to lower-tier storage (data that you want safe but you don&#8217;t need immediate access to, e.g. family photos), with varying prices depending on the service you offer to others. The better the service you offer (the more you put in), the better you get (the more you get out). Of course, those who don&#8217;t want to contribute their resources to the network (or can&#8217;t do so) would be able to pay for some centralised storage.</p>
<p>It&#8217;s not just individuals who could use this system, however. Think about companies with large numbers of desktop machines in geographically distinct locations. Bump up the redundancy factor and it could be licensed as an alternative off-site backup solution. Archived data could be distributed across employees&#8217; desktop computers, using a percentage of the disk space that would otherwise just be sitting idle. For a fee.</p>
<p>Of course, there are a large number of things to consider and tweak, such as how to deal with encryption, and the inevitability of people losing their keys. My first thoughts on this are to have a two-layer system, although I&#8217;m not sure this is possible. The user has a passphrase-protected key that can decrypt a secondary key which is actually centrally stored and used to encrypt/decrypt their files. Then if users lose their passphrase, their data isn&#8217;t lost &#8211; another key held in central reserve that requires a combination of personal details to unlock can be used to decrypt the secondary key and create a replacement personal keypair.</p>
<p>That&#8217;s probably enough about Partis for now!</p>
<p><strong>Update (2008-04-29 18:25):</strong> <a href="http://www.danlester.com/" target="_blank">Dan Lester</a> (who uses the same WP theme &#8211; what are the chances?) has drawn my attention to <a href="http://www.zoogmo.com">Zoogmo</a> which is similar on the surface, but is Windows-only and based around the idea of sharing with friends rather than the Partis network. Also, they don&#8217;t yet appear to have different tiers. They do have a suitable &#8220;Web 2.0&#8243; name though. Something to look into and keep an eye on though. Are any ideas original any more?</p>
<h2>Web service integration</h2>
<p>Something that came to my attention the other day when reading <a href="http://fishbowl.pastiche.org/">Charles Miller&#8217;s blog</a> was the fragmentation of data across the web. There are few central authentication schemes (such as OpenID) and little support for them. There is no standard for integrating the services offered by the multitude of different sites. This isn&#8217;t helped by the lack of incentive for sites to bring their offerings together, but I believe it could be really useful. I then read <a title="The Fishbowl: Function Follows Form" href="http://fishbowl.pastiche.org/2007/05/16/function_follows_form" target="_blank">various</a> <a title="ZefHemel.com: WebFS" href="http://www.zefhemel.com/archives/2007/03/04/webfs" target="_blank">blog</a> <a title="TechFold: Time For An Internet Filesystem?" href="http://techfold.com/2007/04/18/time-for-an-internet-file-system-ifs/">posts</a> on this subject and decided that I would like to hammer out the beginnings of a web interaction/integration API. With help and assistance from other people, of course!</p>
<p>More on this another time. All I will say for now is a potential name: <strong>OpenIntegrate</strong>.</p>
<h2>Pluggable PHP system</h2>
<p>While in the shower the other day (an excellent place for ideas to appear, it seems), I decided that what I really want to create is a library of PHP code that I can just plug together for various tasks. It would have to know a bit about database layout, so that I didn&#8217;t really have to think about it in advance. The more I thought about it, the more developed the idea became. This system would be a set of PHP files and a preprocessor, so that modules can have optional dependencies and hence conditional code generation/inclusion in a fast way, as well as automatically creating/updating the database in order to work.</p>
<p>For example, I was recently thinking about how persistent logins work, and how nice it would be to just write a component once that I can just add to a generic user authentication component. A user authentication component requires (at minimum) a <strong>username</strong> and <strong>password</strong> field in a <strong>users</strong> table of a database. When coupled with a persistent login cookie system, however, either the <strong>users</strong> table has to be updated to include a <strong>persistent_token</strong> field (and maybe a <strong>series_id</strong>, see <a href="http://jaspan.com/improved_persistent_login_cookie_best_practice" target="_blank">here</a>) or a new tables is required if you want to allow login to be remembered from multiple places.</p>
<p>It would be really nice if the PHP could take care of these database modifications by itself, and automatically integrate with the user login module, so that I don&#8217;t have to worry about it. That way, I can just put a load of files together, run something similar to <kbd>rake</kbd>/<kbd>bake</kbd> on them, and end up with an SQL file that will contain the required database schema and also include/exclude bits of the PHP code based on the available modules, perhaps commenting/uncommenting blocks based on available modules, etc. This would prevent a number of checks for optionally available functionality. Each module would then contain a comment header, perhaps something like:</p>
<pre>/*# PROVIDES: userauth
 *# REQUIRES:
 *# SUPPORTS: persistlogin
 *# DEFAULT_DEF: TBL_USER="users"
 *# DB_REQUIRE: [ TBL_USER, [ username: varchar50, password: char32 ] ]
 */</pre>
<p>and then:</p>
<pre>/*# PROVIDES: persistlogin
 *# REQUIRES: userauth
 *# SUPPORTS: persistlogin
 *# DB_REQUIRE: [ TBL_USER, [ persistent_token: char32, series_id: char32 ] ]
 */</pre>
<p>&#8230; and then make a sensible minimum required database structure out of them. Of course, much more than this would be required, and the format described above is very nasty, but that was just my first thoughts. You could then have conditional compilation:</p>
<pre lang="php">/*# IF HAS_MODULE("persistlogin")
  // code to check for persistent login cookie
  if ($_COOKIE['persist_login']) { }
  elseif (/* check DB ... */) {
 *# ELSEIF #*/
  if (/* check DB ... */) {
/*# ENDIF #*/
    // log them in
  } else {
    // ...
  }</pre>
<p>or:</p>
<pre lang="php">/*# IF HAS_MODULE("persistlogin") #*/
  // code to check for persistent login cookie
  if ($_COOKIE['persist_login']) { }
  elseif (/* check DB ... */) {
/*# ELSEIF #*
  if (/* check DB ... */) {
 *# ENDIF #*/
    // log them in
  } else {
    // ...
  }</pre>
<p>depending on whether the &#8220;persistlogin&#8221; module is available at the time the preprocessor is run.</p>
<p>I thought about calling it GHOTI (<a title="Wikipedia: Ghoti" href="http://en.wikipedia.org/wiki/Ghoti" target="_blank">prounounced</a> &#8220;fish&#8221;) because I like quirky words, but couldn&#8217;t immediately come up with a backronym. G- H- Offering Tight Integration? Maybe I&#8217;ll come up with something from Latin instead. Or call it RADPHP or PHP-RAD. Who knows?</p>
<p>Anyway, that&#8217;s probably enough of my random ideas for now. More to come after exams, I don&#8217;t doubt! First one is tomorrow at 14:30. Sigh.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dmi.me.uk/blog/2008/04/29/overflowing-with-ideas/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/3.0/</creativeCommons:license>
	</item>
		<item>
		<title>FolderCheck Thunderbird Extension</title>
		<link>http://www.dmi.me.uk/blog/2007/05/08/foldercheck-thunderbird-extension/</link>
		<comments>http://www.dmi.me.uk/blog/2007/05/08/foldercheck-thunderbird-extension/#comments</comments>
		<pubDate>Tue, 08 May 2007 09:09:00 +0000</pubDate>
		<dc:creator>Dave</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[Personal]]></category>
		<category><![CDATA[Utilities]]></category>

		<guid isPermaLink="false">http://www.dmi.me.uk/blog/2007/05/08/foldercheck-thunderbird-extension/</guid>
		<description><![CDATA[<p>This is something I&#8217;ve been meaning to write for a while, and finally got round to doing. Basically, it&#8217;s a simple Thunderbird extension that makes it easier for you to check other folders for new messages. I&#8217;ve named it FolderCheck* (rather unimaginatively), and it&#8217;s available from the Mozilla Add-ons site sandbox.</p>
<p>The problem is that, at the <a href="http://www.dmi.me.uk/blog/2007/05/08/foldercheck-thunderbird-extension/">[...]</a>]]></description>
			<content:encoded><![CDATA[<p>This is something I&#8217;ve been meaning to write for a while, and finally got round to doing. Basically, it&#8217;s a simple Thunderbird extension that makes it easier for you to check other folders for new messages. I&#8217;ve named it <a href="https://addons.mozilla.org/en-US/thunderbird/addon/4936" target="_blank">FolderCheck</a>* (rather unimaginatively), and it&#8217;s available from the Mozilla Add-ons site sandbox.</p>
<p>The problem is that, at the moment, Thunderbird will only check either the inbox or every folder for messages (for all accounts). This is pretty useless for me, as I only get new email in my inbox for some accounts, and get my email server-sorted into different folders for other accounts. This means that if I want to tell Thunderbird to check a specific folder for messages, I have to right-click the folder, choose &#8220;<u>P</u>roperties&#8221;, check &#8220;<u>C</u>heck this folder for new messages&#8221;, then click OK. And do it all over again for the next folder. And the next. This quickly gets irritating!</p>
<p>My extension adds a new &#8220;C<u>h</u>eck for new items&#8221; item to the context menu for each folder (except Inbox and some other special folders) that allows you to quickly see whether a folder is checked for new messages, and to quickly and easily toggle that setting. Now I just have to right-click each folder and hit &#8220;h&#8221; to toggle the setting.</p>
<p>Coming soon (when I get round to it): a dedicated window to make multiple folder selection easy. My current thought is a list of folders with a filter box and &#8220;(De)Select All Visible Folders&#8221; buttons.</p>
<p>* Note: currently requires a free Mozilla Developer account, as it&#8217;s not yet a public extension.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dmi.me.uk/blog/2007/05/08/foldercheck-thunderbird-extension/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/3.0/</creativeCommons:license>
	</item>
		<item>
		<title>Coolermaster CoolDrive 6</title>
		<link>http://www.dmi.me.uk/blog/2007/04/07/coolermaster-cooldrive-6/</link>
		<comments>http://www.dmi.me.uk/blog/2007/04/07/coolermaster-cooldrive-6/#comments</comments>
		<pubDate>Sat, 07 Apr 2007 23:51:37 +0000</pubDate>
		<dc:creator>Dave</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[Utilities]]></category>

		<guid isPermaLink="false">http://www.dmi.me.uk/blog/2007/04/07/coolermaster-cooldrive-6/</guid>
		<description><![CDATA[<p>Well this has been a bit of a saga so far. I&#8217;ve been working on Linux support for the CoolerMaster CoolDrive 6 (CD6 henceforth) which I currently have in my computer. It has a USB connection, and an inbuilt Prolific PL2303X USB-Serial converter. Sadly, I&#8217;ve been struggling with uncooperative C code that I&#8217;d found which supposedly <a href="http://www.dmi.me.uk/blog/2007/04/07/coolermaster-cooldrive-6/">[...]</a>]]></description>
			<content:encoded><![CDATA[<p>Well this has been a bit of a saga so far. I&#8217;ve been working on Linux support for the CoolerMaster CoolDrive 6 (CD6 henceforth) which I currently have in my computer. It has a USB connection, and an inbuilt Prolific PL2303X USB-Serial converter. Sadly, I&#8217;ve been struggling with uncooperative C code that I&#8217;d found which <em>supposedly</em> allows me to control a serial port. Yeah, right.</p>
<p><span id="more-17"></span><br />
I&#8217;ve got the source from the CoolerMaster-provided programs that deal with the device, so all I need to do is get serial communication working (9600 baud, 8 data bits, 1 stop bit, no parity or handshaking) and I should be good to go. This will have the following advantages:</p>
<ol>
<li>My processor fan is connected to the <strong>FAN1</strong> output of the CD6. It would be quite nice to software-control (and -read) its speed depending on whether I want cool operation or silence.</li>
<li>The internal HDD fan is hardwired to the <strong>FAN3</strong> output of the CD6. It would be quite nice to software-control (and -read) its speed etc&#8230; especially as I don&#8217;t really currently use it.</li>
<li>My other case fans are currently controlled by a switch I&#8217;ve modded into a bay bevel. It would be great to take away the hardware from this too so that all fans in my computer are software-controlled. To do this, I can simply attach a couple of transistors to some cables going to <strong>FAN2</strong>, and then they will switch the fans on and off depending on whether <strong>FAN2</strong> is on or off.</li>
</ol>
<p>The end result? I want to be able to press a button on my keyboard (the backlight button, in fact), and turn off the backlight on my keyboard, the case fans, case glow and HDD fan, and to slow my CPU fan down to about 1700 RPM. Another press of the button will activate the backlight, case fans, case glow and HDD fan and speed the CPU fan up to 2300 RPM or so. That way, I can watch films/videos or sleep in near-silence with a simple keystroke, and go back to intense operation just as quickly. I could even decide that I wanted to do some compiling while I was away from my machine, and turn the fans on via SSH.</p>
<p>The possibilities are (obviously) endless.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dmi.me.uk/blog/2007/04/07/coolermaster-cooldrive-6/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/3.0/</creativeCommons:license>
	</item>
		<item>
		<title>Automatic email forwarding</title>
		<link>http://www.dmi.me.uk/blog/2007/03/08/automatic-email-forwarding/</link>
		<comments>http://www.dmi.me.uk/blog/2007/03/08/automatic-email-forwarding/#comments</comments>
		<pubDate>Thu, 08 Mar 2007 09:19:09 +0000</pubDate>
		<dc:creator>Dave</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[University]]></category>
		<category><![CDATA[Utilities]]></category>

		<guid isPermaLink="false">http://www.dmi.me.uk/2007/03/08/automatic-email-forwarding/</guid>
		<description><![CDATA[<p>Well I got fed up with email filter rules last week, and this is the rather bizarre result: autoforward, a Perl script and configuration file that will automatically generate Exim filter files (.forward files), mainly to be used on my University account. My email processing rules have become pretty complex and messy, making them difficult to <a href="http://www.dmi.me.uk/blog/2007/03/08/automatic-email-forwarding/">[...]</a>]]></description>
			<content:encoded><![CDATA[<p>Well I got fed up with email filter rules last week, and this is the rather bizarre result: <em>autoforward</em>, a Perl script and configuration file that will automatically generate Exim filter files (.forward files), mainly to be used on my University account. My email processing rules have become pretty complex and messy, making them difficult to control, and there&#8217;s a lack of uniformity about them. I decided there had to be a better way, so set about writing a configuration format and parser&#8230; and I think I succeeded.</p>
<p><span id="more-6"></span></p>
<p>The configuration file format is pretty simple. There are some global options that must be set, and then sections named after the directory to which they filter mail.  These sections then contain some (optional) meta-actions (e.g. automatic archiving by date or automatic reply), one or more matching rules (i.e. how to decide if an email message should be processed by this rule) and then zero or more actions to be taken (the default being &#8220;save to the given folder and stop processing&#8221;). Let&#8217;s take a look at a (very simple) example:</p>
<pre>[!GLOBAL!]
mail-root = "IMAP"
errors-to = "errors"

vacation-level = 0
vacation-alias = my.user@my.university.ac.uk myabbr@my.university.ac.uk
vacation-msg = $home/vacation/message
vacation-log = $home/vacation/log
vacation-once = $home/vacation/once
vacation-repeat = 2d

archive-path = "IMAP/archive/$1/"

[spam]
group
  header X-Spam-Flag  == "YES"
  header Subject      =~ "^((my|new)s)?PH[a-z]*A?[a-z]*R[a-z]*MA"
  header Subject      =~ "^ME[a-z]*DS"
endgroup
and
!anydomain             "my\.university\.ac\.uk"

[!UNDELIVERED!]
@ARCHIVE INBOX
@VACATION 4

saveto .email</pre>
<p>Wow. What the hell does that all mean? Allow me to explain.</p>
<p>The first part deals with global settings, including:</p>
<ul>
<li>The root directory that mail should be stored in</li>
<li>The directory that error messages should be stored in</li>
<li>The current &#8220;vacation level&#8221; and other settings related to it (see later)</li>
<li>The directory that automatic archive copies should be stored in (see later)</li>
</ul>
<p>After that follows a filter rule for email to be put into /spam. I first create a nested rule that checks if the X-Spam-Flag header is set to &#8220;YES&#8221; or the subject matches one of two patterns that came up very frequently for a while. It then also checks against bizarre false positives by ensuring that the &#8220;from&#8221; domain does not match my university&#8217;s domain (or any of its subdomains, like lecturer@dept.my.university.ac.uk). Sadly, Exim is very strange about its quoting rules, and that is the reason for the multiple backslashes. Maybe that will be tidied in a future release <img src='http://www.dmi.me.uk/blog/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' title="icon smile photo" /> </p>
<p>The final rule deals with any email that hasn&#8217;t been delivered yet, and is a special rule (as evidenced by the exclamation marks and capital letters). This rule contains two meta-actions. The first tells it to automatically archive email by date to IMAP/archive/yyyy-mm/INBOX. The next meta-action says that if the &#8220;vacation-level&#8221; variable is 4 or higher and the email was sent directly to me, automatically reply to the sender. Finally, there&#8217;s an actual action that causes the email to be saved to my .email file.</p>
<p>For the curious, this turns out to be something like the following, when run through <em>autoforward</em>:</p>
<pre># Exim filter  &lt;&lt;== do not edit or remove this line!if error_message then

  save IMAP/errors

  finish
endif

add 0 to n0

############################################################
## Dir: spam
############################################################

if (
  $h_X-Spam-Flag: is "YES"
  or $h_Subject: matches "^((my|new)\s)?PH[a-z]*A?[a-z]*R[a-z]*MA"
  or $h_Subject: matches "^ME[a-z]*DS"
)
and foranyaddress $h_From:,$h_Reply-To:
  ($thisaddress does not match "@([^@]+.)?my\\.university\\.ac\\.uk")
then

  save IMAP/spam

  finish
endif

###########
## INBOX ##
###########

if not delivered
then
  if $tod_log matches "^(....-..)" then
    save IMAP/archive/$1/INBOX
  endif

  if personal alias my.user@my.university.ac.uk alias myabbr@my.university.ac.uk
  and $n0 is above 3 then
    mail
      to $reply_address
      subject "Re: $h_subject:"
      expand file $home/vacation/message
      log  $home/vacation/log
      once $home/vacation/once
      once_repeat 2d
  endif

  save .email

  finish
endif</pre>
<p>So, if you want to try it, see the attached script and example files, as there&#8217;s much more you can do with it!</p>
<ul>
<li><a href="http://www.dmi.me.uk/blog/wp-content/uploads/2007/03/autoforward.pl">autoforward.pl</a></li>
<li><a href="http://www.dmi.me.uk/blog/wp-content/uploads/2007/03/autoforwardsample.conf">autoforward.sample.conf</a></li>
</ul>
<p>To run the script, you should type something like:</p>
<p>autoforward.pl &lt; ~/autoforward.conf &gt; ~/.forward</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dmi.me.uk/blog/2007/03/08/automatic-email-forwarding/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/3.0/</creativeCommons:license>
	</item>
		<item>
		<title>My current projects</title>
		<link>http://www.dmi.me.uk/blog/2007/03/08/my-current-projects/</link>
		<comments>http://www.dmi.me.uk/blog/2007/03/08/my-current-projects/#comments</comments>
		<pubDate>Thu, 08 Mar 2007 01:01:14 +0000</pubDate>
		<dc:creator>Dave</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[Work]]></category>

		<guid isPermaLink="false">http://www.dmi.me.uk/2007/03/08/my-current-projects/</guid>
		<description><![CDATA[<p>So, what am I working on at the moment?</p>
<p> A very brief list:</p>

[secret project]

This one&#8217;s the biggie. It&#8217;s a company project, so I can&#8217;t reveal anything about it, but it should be launching this summer. Stay tuned for more information as it develops.


RageControl

A website/hosting control panel system. I&#8217;m building this because I haven&#8217;t yet found a <a href="http://www.dmi.me.uk/blog/2007/03/08/my-current-projects/">[...]</a>]]></description>
			<content:encoded><![CDATA[<p>So, what am I working on at the moment?</p>
<p><span id="more-5"></span> A very brief list:</p>
<ul>
<li>[secret project]
<ul>
<li>This one&#8217;s the biggie. It&#8217;s a company project, so I can&#8217;t reveal anything about it, but it should be launching this summer. Stay tuned for more information as it develops.</li>
</ul>
</li>
<li>RageControl
<ul>
<li>A website/hosting control panel system. I&#8217;m building this because I haven&#8217;t yet found a control panel system that I like, and my company will eventually be offering web hosting. At the moment, it just runs on my personal machine, but so far, so good&#8230;</li>
</ul>
</li>
<li>Partis
<ul>
<li>This could become one of many things, and it&#8217;s hard to decide exactly which direction I want to take it in. It&#8217;s either a massively distributed peer-to-peer backup system, or it&#8217;s a way of automatically synchronising groups of files. Maybe I&#8217;ll split the file synch off into another project though.</li>
</ul>
</li>
<li>DBFS
<ul>
<li>A database-based filesystem, possibly as a final (4th) year individual project for my Computing degree&#8230; It has a few novel features that I haven&#8217;t seen proposed anywhere else, but it may require me writing/modifying a database engine.</li>
</ul>
</li>
</ul>
<p>&#8230; and then there&#8217;s the <a href="http://www.retiarius-ltd.co.uk/" title="Retiarius Ltd" target="_blank">Retiarius</a> site to work on and finish, not to mention all the other hundreds of little ideas that keep surfacing!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dmi.me.uk/blog/2007/03/08/my-current-projects/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/3.0/</creativeCommons:license>
	</item>
	</channel>
</rss>
