<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">
<channel>
<title>Mark Aufflick's Weblog</title>
<link>http://mark.aufflick.com/blog/</link>
<description>Mark Aufflick's Weblog</description>
<generator>OpenACS 5.0</generator>
<lastBuildDate>Thu, 02 Aug 2012 02:25:20 GMT</lastBuildDate>
<image>
<title>Mark Aufflick's Weblog</title>
<url>http://mark.aufflick.com/rss-support/images/openacs_logo_rss.gif</url>
<link>http://mark.aufflick.com/blog/</link>
<width>126</width>
<height>48</height>
</image>
<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/MarkAufflicksWeblog" /><feedburner:info uri="markaufflicksweblog" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><geo:lat>-33.832</geo:lat><geo:long>151.218</geo:long><feedburner:browserFriendly>This is an XML content feed. It is intended to be viewed in a newsreader or syndicated to another site, subject to copyright and fair use.</feedburner:browserFriendly><item>
<title>AQXMLParser + OAuth</title>
<link>http://feedproxy.google.com/~r/MarkAufflicksWeblog/~3/rlHEpIyh8mg/aqxmlparser-oauth</link>
<guid isPermaLink="false">http://mark.aufflick.com/blog/2012/08/02/aqxmlparser-oauth</guid>
<description>&lt;p&gt;I've been enjoying using Jim Dovey's excellent AQXMLParser lately, and in fact am giving a talk on it tonight at Sydney CocoaHeads. To use it in a new project, I need to be able to authorise the outbound REST request with some OAuth 1 tokens etc.&lt;/p&gt;
&lt;p&gt;OAuth can be a right pain, and the Cocoa implementations aren't awesome. gtm-oauth (the OAuth 1 library from the Google Toolbox for Mac) is a little odd in its implementation, but doing your own OAuth implementation would be so tedious it's one of the better options out there.&lt;/p&gt;
&lt;p&gt;It's all pretty easy. Firstly, use gtm-oauth like normal to have your user authorise your app and receive a token.&lt;/p&gt;
&lt;p&gt;Next, to make a request, gtm-oauth provides a way to authorise an NSMutableURLRequest, but AQXMLParser uses it's own HTTPMessage class (which wraps the lower level CFHTTPMessage from Core Foundation).&lt;/p&gt;
&lt;p&gt;What I have done is extend HTTPMessage to provide a copy of itself as an NSURLRequest, and then write a category that auths that with gtm-oauth and then cribs the headers from that and applies them to the HTTPMessage. It's a little roundabout, but because of the need to sign the whole request and the way that gtm-oauth internals work, anything else would be very complicated. So in use, it looks like this:&lt;/p&gt;
&lt;blockquote&gt;&lt;tt&gt;
&lt;p&gt;#import "HTTPMessage+GTMOAuth.h"&lt;/p&gt;
&lt;p&gt;...&lt;/p&gt;
&lt;p&gt;GTMOAuthAuthentication * oauth = ...; // &lt;a href="http://code.google.com/p/gtm-oauth/wiki/GTMOAuthIntroduction"&gt;setup gtm-oauth like normal&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;HTTPMessage * myMessage = ...; // &lt;a href="http://quatermain.tumblr.com/parser-example"&gt;create the http request like normal&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[myMessage authorizeWithGTMOAuth:oauth];&lt;/p&gt;
&lt;p&gt;// now create the parser and use the http message etc. like normal&lt;/p&gt;
&lt;/tt&gt;&lt;/blockquote&gt;
&lt;p&gt;For now the changes and category are only in my fork, but I have a &lt;a href="https://github.com/AlanQuatermain/aqtoolkit/pull/15"&gt;pending pull request&lt;/a&gt; with Jim that I will work out the best way to incorporate them into his master repository. My fork also contains tweaks to work with the latest llvm and ARC (although note neither gtm-oauth nor HTTPMessage or AQXMLParser use ARC, so you'll have to add the -fno-objc-arc compiler flag where appropriate).&lt;/p&gt;
&lt;p&gt;gtm-outh:�&lt;a href="http://code.google.com/p/gtm-oauth/"&gt;http://code.google.com/p/gtm-oauth/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;My fork of aqtoolkit:�&lt;a href="https://github.com/aufflick/aqtoolkit"&gt;https://github.com/aufflick/aqtoolkit&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=rlHEpIyh8mg:pXOzurQWs-M:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=rlHEpIyh8mg:pXOzurQWs-M:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?i=rlHEpIyh8mg:pXOzurQWs-M:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=rlHEpIyh8mg:pXOzurQWs-M:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?i=rlHEpIyh8mg:pXOzurQWs-M:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=rlHEpIyh8mg:pXOzurQWs-M:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?i=rlHEpIyh8mg:pXOzurQWs-M:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=rlHEpIyh8mg:pXOzurQWs-M:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MarkAufflicksWeblog/~4/rlHEpIyh8mg" height="1" width="1"/&gt;</description>
<pubDate>Thu, 02 Aug 2012 02:25:20 GMT</pubDate>
<feedburner:origLink>http://mark.aufflick.com/blog/2012/08/02/aqxmlparser-oauth</feedburner:origLink></item>
<item>
<title>supervisord supervisorctl cheat sheet</title>
<link>http://feedproxy.google.com/~r/MarkAufflicksWeblog/~3/BK6vjj6GWtw/supervisord-supervisorctl-cheat-sheet</link>
<guid isPermaLink="false">http://mark.aufflick.com/blog/2012/03/25/supervisord-supervisorctl-cheat-sheet</guid>
<description>&lt;p&gt;On my new server I made the switch from daemontools to supervisor. As if to make daemontools users feel at home the documentation for supervisorctl use is a bit thin :)&lt;br /&gt;So far my biggest gotcha was that after adding a new .conf file in your includes (or to the main file itself, but you wouldn't do that would you?) is that you need to do *both* of the following:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;gt; &lt;strong&gt;supervisorctl reread&lt;/strong&gt;&lt;br&gt;
new.app.conf: available&lt;br&gt;
&amp;gt; &lt;strong&gt;supervisorctl update&lt;/strong&gt;&lt;br&gt;
new.app.conf: added process group&lt;br&gt;
&amp;gt; &lt;strong&gt;supervisorctl&lt;/strong&gt;&lt;br&gt;
new.app � � � � RUNNING ...
&lt;/blockquote&gt;
&lt;p&gt;�&lt;/p&gt;

&lt;h3&gt;haproxy&lt;/h3&gt;
&lt;p&gt;Unfortunately supervisor doesn't offer a way to provide a custom restart command, so doing an uninterrupted haproxy restart via supervisor isn't possible. Instead make sure you have autorestart set to unexpected (the default) rather than true (which is what I usually do) - that way if you want a clean haproxy restart you can just do it yourself at the commandline using the -sf option as normal.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=BK6vjj6GWtw:jLGOTve-qL0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=BK6vjj6GWtw:jLGOTve-qL0:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?i=BK6vjj6GWtw:jLGOTve-qL0:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=BK6vjj6GWtw:jLGOTve-qL0:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?i=BK6vjj6GWtw:jLGOTve-qL0:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=BK6vjj6GWtw:jLGOTve-qL0:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?i=BK6vjj6GWtw:jLGOTve-qL0:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=BK6vjj6GWtw:jLGOTve-qL0:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MarkAufflicksWeblog/~4/BK6vjj6GWtw" height="1" width="1"/&gt;</description>
<pubDate>Sun, 25 Mar 2012 23:14:32 GMT</pubDate>
<feedburner:origLink>http://mark.aufflick.com/blog/2012/03/25/supervisord-supervisorctl-cheat-sheet</feedburner:origLink></item>
<item>
<title>SAPI Cocoa SDK</title>
<link>http://feedproxy.google.com/~r/MarkAufflicksWeblog/~3/zfzBsRasFqw/sapi-cocoa-sdk</link>
<guid isPermaLink="false">http://mark.aufflick.com/blog/2012/03/24/sapi-cocoa-sdk</guid>
<description>The Cocoa Sensis SAPI SDK is live, ready for this weekend's Sensis SAPI hackathon. https://github.com/pumptheory/SAPI-Cocoa-SDK

&lt;img src="http://img.tweetimag.es/i/SensisAPI_b" alt="SAPI Logo" align="middle"&gt; &lt;img src="http://developers.sensis.com.au/files/yp-api-poweredby-sticky-71x78.png" alt="Yellow Pages Logo" align="middle"&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=zfzBsRasFqw:tPg-oBtgg1g:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=zfzBsRasFqw:tPg-oBtgg1g:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?i=zfzBsRasFqw:tPg-oBtgg1g:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=zfzBsRasFqw:tPg-oBtgg1g:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?i=zfzBsRasFqw:tPg-oBtgg1g:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=zfzBsRasFqw:tPg-oBtgg1g:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?i=zfzBsRasFqw:tPg-oBtgg1g:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=zfzBsRasFqw:tPg-oBtgg1g:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MarkAufflicksWeblog/~4/zfzBsRasFqw" height="1" width="1"/&gt;</description>
<pubDate>Sat, 24 Mar 2012 01:13:24 GMT</pubDate>
<feedburner:origLink>http://mark.aufflick.com/blog/2012/03/24/sapi-cocoa-sdk</feedburner:origLink></item>
<item>
<title>Stunnel + Thin + Rails for the world's easiest ssl hosting</title>
<link>http://feedproxy.google.com/~r/MarkAufflicksWeblog/~3/jeSdACnk6iQ/stunnel-thin-rails-for-the-world-s-easiest-ssl-hosting</link>
<guid isPermaLink="false">http://mark.aufflick.com/blog/2012/03/20/stunnel-thin-rails-for-the-world-s-easiest-ssl-hosting</guid>
<description>&lt;p&gt;These days I do most quick and dirty web stuff with Ruby on Rails, and any open source web stuff I install I prefer Rails based code for easy hacking.�Every so often you want to host something for internal or other small-volume usage, but it has to be SSL. Traditionally this is a pain in the backside, especially with Rails. Back in the day I did everything with &lt;a href="http://openacs.org"&gt;OpenACS&lt;/a&gt; or plain &lt;a href="http://aolserver.com"&gt;AOLServer&lt;/a&gt;. This meant I had to install a bunch of stuff by hand (although debian packages are now available), but once it was done it was a simple config tweak to change the number of threads and/or add ssl etc.�With Rails it's kind of the opposite. Getting things up and running is incredibly easy, but scaling it or adding ssl usually means �Apache, or Nginx, or some other (relatively) heavy server plus other stuff. Doing this all as a non-super user is even more painful.&lt;/p&gt;
&lt;p&gt;For a client I wanted to setup a &lt;a href="http://redmine.org"&gt;Redmine&lt;/a&gt; instance for a wiki and browsing internal git repositories. It's a Rails 2.x app. Initial setup is easy. Using the latest trunk version of Redmine (which supports Ruby 1.9 and uses bundler) it's a simple matter of the following steps (which assume pretty much nothing is installed except base libraries like sqlite3):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;checking out the svn trunk&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote class="sourcebox" style="border-left: 5px solid #ccc; margin-left: 45px; padding-left: 5px; color: #000000; background-color: #ffffff;"&gt;
&lt;p&gt;svn co svn co http://redmine.rubyforge.org/svn/trunk redmine&lt;br /&gt;cd �redmine&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;installing &lt;a href="http://beginrescueend.com"&gt;rvm&lt;/a&gt;,�setting up the right ruby &amp;amp; gem set&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote class="sourcebox" style="border-left: 5px solid #ccc; margin-left: 45px; padding-left: 5px; color: #000000; background-color: #ffffff;"&gt;
&lt;p&gt;bash &lt;span style="color: #ff0000;"&gt;-s&lt;/span&gt; stable &amp;lt; &amp;lt;(curl &lt;span style="color: #ff0000;"&gt;-s&lt;/span&gt; https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer)&lt;br /&gt;. ~/.bashrc&lt;br /&gt;rvm install ruby-1.9.3&lt;br /&gt;rvm use ruby-1.9.3@redmine &lt;span style="color: #ff0000;"&gt;--create&lt;/span&gt;&lt;br /&gt;rvm install bundler&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;installing bundler and using it to prepare all the ruby gems (I am using sqlite and don't have mysql libraries installed)&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote class="sourcebox" style="border-left: 5px solid #ccc; margin-left: 45px; padding-left: 5px; color: #000000; background-color: #ffffff;"&gt;
&lt;p&gt;gem install bundler&lt;br /&gt;bundle install &lt;span style="color: #ff0000;"&gt;--without=mysql&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;follow the main redmine installation steps from step 3, but make the database adapter sqlite3 and the database db/production.sqlite&lt;br /&gt;&lt;a href="http://www.redmine.org/projects/redmine/wiki/RedmineInstall"&gt;http://www.redmine.org/projects/redmine/wiki/RedmineInstall&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You now have Redmine up and running, via the test webrick server, on port 3000. But that's no good for two reasons, one we obviously don't have ssl, and two webrick is a single process (and ruby is always a single processor thread) so it's not very scalable.&lt;/p&gt;
&lt;p&gt;A nice simple, and yet fast, way to scale Ruby http servers is &lt;a href="http://code.macournoyer.com/thin/"&gt;Thin&lt;/a&gt;. It's Ruby and C. It's only http though, so we need to put ssl in front some how. A great way of doing this is &lt;a href="http://www.stunnel.org/"&gt;stunnel&lt;/a&gt;, which can tunnel just about anything to anything when it comes to ssl. So we run a couple of Thin instances, and stunner to proxy it to ssl. The great thing is we can arrange for the communication between the two to be via Unix sockets so we don't even need to reserve localhost TCP ports?so we can scale the number of instances without checking with anyone else.&lt;/p&gt;
&lt;p&gt;Here are my steps for Thin and stunnel:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Install Thin:&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote class="sourcebox" style="border-left: 5px solid #ccc; margin-left: 45px; padding-left: 5px; color: #000000; background-color: #ffffff;"&gt;
&lt;p&gt;gem install thin&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Install stunnel:&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote class="sourcebox" style="border-left: 5px solid #ccc; margin-left: 45px; padding-left: 5px; color: #000000; background-color: #ffffff;"&gt;
&lt;p&gt;# get the latest version of stunner from�&lt;a href="http://www.stunnel.org/?page=downloads"&gt;http://www.stunnel.org/?page=downloads&lt;br /&gt;&lt;/a&gt;tar zxf stunnel-4.xx.tar.gz&lt;br /&gt;cd stunnel-4.xx&lt;br /&gt;mkdir ~/usr�&lt;br /&gt;./configure &lt;span style="color: #ff0000;"&gt;--prefix=~/usr &lt;/span&gt;&lt;br /&gt;make&lt;br /&gt;make install&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;You need a .pem certificate for stunnel. If you don't have a real certificate, you can create a self-signed one like so:&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote class="sourcebox" style="border-left: 5px solid #ccc; margin-left: 45px; padding-left: 5px; color: #000000; background-color: #ffffff;"&gt;
&lt;p&gt;openssl req &lt;span style="color: #ff0000;"&gt;-new -x509 -days &lt;/span&gt;365 &lt;span style="color: #ff0000;"&gt;-nodes -config&lt;/span&gt; stunnel.cnf &lt;span style="color: #ff0000;"&gt;-out&lt;/span&gt; stunnel.pem &lt;span style="color: #ff0000;"&gt;-keyout &lt;/span&gt;my_stunnel.pem&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;where the stunnel.cnf file is in the source distribution. Answer the questions appropriately.&lt;/li&gt;
&lt;li&gt;stunnel needs a config file, something like this (in this case for three thin instances)&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote class="sourcebox" style="border-left: 5px solid #ccc; margin-left: 45px; padding-left: 5px; color: #000000; background-color: #ffffff;"&gt;
&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 13.0px Monaco;"&gt;&lt;span style="font-family: Monaco; font-size: 12px;"&gt;&lt;span style="color: #a0532d;"&gt;pid&lt;/span&gt; = &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: Monaco; font-size: 12px;"&gt; &lt;span style="color: #a0532d;"&gt;cert&lt;/span&gt; = /path/to/my_stunnel.pem&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="font-family: Monaco; font-size: 12px;"&gt; [&lt;span style="color: #208b22;"&gt;redmine&lt;/span&gt;]&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: Monaco; font-size: 12px;"&gt; &lt;span style="color: #a0532d;"&gt;accept&lt;/span&gt; = 12345&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #a0532d; font-family: Monaco; font-size: 12px;"&gt; connect&lt;/span&gt; = /path/to/my_rails_app/tmp/thin.0.sock&lt;/p&gt;
&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 13.0px Monaco;"&gt;&lt;span style="color: #a0532d; font-family: Monaco; font-size: 12px;"&gt;connect&lt;/span&gt; = /path/to/my_rails_app/tmp/thin.1.sock&lt;/p&gt;
&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 13.0px Monaco;"&gt;&lt;span style="color: #a0532d; font-family: Monaco; font-size: 12px;"&gt;connect&lt;/span&gt; = /path/to/my_rails_app/tmp/thin.2.sock&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;start up stunnel&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote class="sourcebox" style="border-left: 5px solid #ccc; margin-left: 45px; padding-left: 5px; color: #000000; background-color: #ffffff;"&gt;
&lt;p&gt;~/usr/bin/stunnel /path/to/my/stunnel.conf&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span style="line-height: 0px;"&gt; start up your rails app with Thin&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote class="sourcebox" style="border-left: 5px solid #ccc; margin-left: 45px; padding-left: 5px; color: #000000; background-color: #ffffff;"&gt;
&lt;p&gt;thin start &lt;span style="color: #ff0000;"&gt;-s3&lt;/span&gt; --socket /path/to/my_rails_app/tmp/thin.sock &lt;span style="color: #ff0000;"&gt;-e&lt;/span&gt; production&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And that's it, your site running on https port 12345! All this has not required root access at any point. If you want to listen on a low port, eg. 443, the only thing that needs to run as root is stunnel.&lt;/p&gt;
&lt;p&gt;But don't break out the champagne yet - we have a problem. Your rails app knows the hostname and port thanks to the Host: header, but it�has no idea that it's running behind stunnel and is therefore ssl. This is only a problem in the occasions where a full url is needed, and the primary case is for http redirect headers. I take care of this by rewriting the Location header in application_controller.rb:&lt;/p&gt;
&lt;blockquote class="sourcebox" style="border-left: 5px solid #ccc; margin-left: 45px; padding-left: 5px; color: #000000; background-color: #ffffff;"&gt;
&lt;pre style="margin: 0.0px 0.0px 13.0px 0.0px; font: 12.0px Monaco;"&gt;after_filter &lt;span style="color: #008b8b;"&gt;:force_https_for_redirects&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #7f007f;"&gt;def &lt;/span&gt; &lt;span style="color: #3800ff;"&gt;force_https_for_redirects&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #7f007f;"&gt; if&lt;/span&gt; response.headers.has_key?(&lt;span style="color: #8b2252;"&gt;"Location"&lt;/span&gt;)&lt;br /&gt; response.headers[&lt;span style="color: #8b2252;"&gt;"Location"&lt;/span&gt;].sub!(&lt;span style="color: #8b2252;"&gt;/^http:/&lt;/span&gt;, &lt;span style="color: #8b2252;"&gt;'https:'&lt;/span&gt;)&lt;br /&gt; &lt;span style="color: #7f007f;"&gt; end&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #7f007f;"&gt;end&lt;/span&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;You may have other cases that need fixing, like constructing urls for emails. Note that I wouldn't recommend mucking about with the X-Forwarded-Proto patches for stunnel. I just don't trust third party patches for security software, and in any case I'm not sure it would work with using Unix sockets for the intermediary transport.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; Here's how to monkey patch ActionController::UrlWriter::url_for() so your emails will have correct links. In Rails 2 (in my case for redmine), I did it in environment.rb - for Rails 3 I think you could do it in application.rb, but it doesn't really matter where you do it as long as it gets compiled after ActionController::UrlWriter is loaded.&lt;/p&gt;
&lt;blockquote class="sourcebox" style="border-left: 5px solid #ccc; margin-left: 45px; padding-left: 5px; color: #000000; background-color: #ffffff;"&gt;
&lt;pre style="margin: 0.0px 0.0px 13.0px 0.0px; font: 12.0px Monaco;"&gt;&lt;span style="color: #7e297f;"&gt;module &lt;/span&gt; &lt;span style="color: #228b23;"&gt;ActionController&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: #7e297f;"&gt;  module &lt;/span&gt; &lt;span style="color: #228b23;"&gt;UrlWriter&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #7e297f;"&gt;    alias &lt;/span&gt; &lt;span style="color: #038b8b;"&gt;:original_url_for&lt;/span&gt; &lt;span style="color: #038b8b;"&gt;:url_for&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #7e297f;"&gt;    def &lt;/span&gt; &lt;span style="color: #353ff9;"&gt;url_for&lt;/span&gt;(options = {})&lt;br /&gt;      options[&lt;span style="color: #038b8b;"&gt;:host&lt;/span&gt;] = &lt;span style="color: #8a2452;"&gt;'efserv.com'&lt;/span&gt; &lt;span style="color: #7e297f;"&gt;unless&lt;/span&gt; options[&lt;span style="color: #038b8b;"&gt;:host&lt;/span&gt;]&lt;br /&gt;      options[&lt;span style="color: #038b8b;"&gt;:protocol&lt;/span&gt;] = &lt;span style="color: #8a2452;"&gt;'https'&lt;/span&gt; &lt;span style="color: #7e297f;"&gt; unless&lt;/span&gt; options[&lt;span style="color: #038b8b;"&gt;:protocol&lt;/span&gt;]&lt;br /&gt;      options[&lt;span style="color: #038b8b;"&gt;:port&lt;/span&gt;] = 7022 &lt;span style="color: #7e297f;"&gt; unless&lt;/span&gt; options[&lt;span style="color: #038b8b;"&gt;:port&lt;/span&gt;]&lt;br /&gt; &lt;br /&gt;      original_url_for(options)&lt;br /&gt;    &lt;span style="color: #7e297f;"&gt;    end&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: #7e297f;"&gt;  end&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #7e297f;"&gt;end&lt;/span&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;�&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=jeSdACnk6iQ:WhwP-dcwPMU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=jeSdACnk6iQ:WhwP-dcwPMU:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?i=jeSdACnk6iQ:WhwP-dcwPMU:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=jeSdACnk6iQ:WhwP-dcwPMU:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?i=jeSdACnk6iQ:WhwP-dcwPMU:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=jeSdACnk6iQ:WhwP-dcwPMU:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?i=jeSdACnk6iQ:WhwP-dcwPMU:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=jeSdACnk6iQ:WhwP-dcwPMU:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MarkAufflicksWeblog/~4/jeSdACnk6iQ" height="1" width="1"/&gt;</description>
<pubDate>Tue, 20 Mar 2012 01:52:39 GMT</pubDate>
<feedburner:origLink>http://mark.aufflick.com/blog/2012/03/20/stunnel-thin-rails-for-the-world-s-easiest-ssl-hosting</feedburner:origLink></item>
<item>
<title>PMPKVObservation ? Yet Another KVO-improvement project</title>
<link>http://feedproxy.google.com/~r/MarkAufflicksWeblog/~3/wEJkYy3seWQ/pmpkvobservation-yet-another-kvo-improvement-project</link>
<guid isPermaLink="false">http://mark.aufflick.com/blog/2012/03/13/pmpkvobservation-yet-another-kvo-improvement-project</guid>
<description>&lt;p&gt;If you?re reading this then you?re probably as frustrated by seemingly random KVO crashes and/or the pain of huge if/else blocks in your observers. I?ve never been happy with the other KVO-improvement classes I?ve seen, and never having had any bright insights myself I kept doing things the normal way. This becomes especially painful with things like view based NSTableViews when you are re-using objects and so need to observe a new object, being very careful to un-observe the prior object (unless it?s been released, which you need to either track yourself if you can, or retain it, which has its own problems).&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;It was clear that the dealloc swizzling approach of Mike Ash?s &lt;a href="https://github.com/mikeash/MAKVONotificationCenter"&gt;MAKVONotificationCenter&lt;/a&gt; was unavoidable, but I didn?t like the complexity. Recently Gwynne Raskind posted a &lt;a href="http://www.mikeash.com/pyblog/friday-qa-2012-03-02-key-value-observing-done-right-take-2.html"&gt;somewhat updated MAKVONotificationCenter&lt;/a&gt; which sparked some discussion, including a comment discussing &lt;a href="https://github.com/nevyn/SPSuccinct/blob/master/SPSuccinct/SPKVONotificationCenter.m"&gt;SPKVONotificationCenter&lt;/a&gt; by Joachim Bengtsson. Joachim?s brainwave was that observations should be modelled as standalone objects and simply managing the lifecycle of that object appropriately should remove the observation. Clean and simple.&lt;/p&gt;
&lt;p&gt;Except it?s not quite that simple because you still need to swizzle the dealloc of the observed object since it can go away at any time. And as much as I love a good macro as much as the next hacker, Joachim?s $depends() macro looks about as much fun as a &lt;a href="http://okmij.org/ftp/Computation/Make-functional.txt"&gt;turing complete makefile&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Enter &lt;a href="https://github.com/aufflick/PMPKVObservation"&gt;PMPKVObservation&lt;/a&gt;!&lt;/h3&gt;
&lt;p&gt;Include PMPKVObservation.m and .h in your project, then do something like:&lt;/p&gt;
&lt;blockquote class="sourcebox" style="border-left: 5px solid #ccc; margin-left: 45px; padding-left: 5px; color: #000000; background-color: #ffffff;"&gt;
&lt;pre style="margin: 0.0px 0.0px 13.0px 0.0px; font: 12.0px Monaco;"&gt;&lt;span style="color: #7a378b;"&gt;#import&lt;/span&gt; &lt;span style="color: #8a2452;"&gt;"PMPKVObservation.h"&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color: #7e297f;"&gt;@interface &lt;/span&gt; &lt;span style="color: #228b23;"&gt;PMPKVOTests&lt;/span&gt; ()&lt;br /&gt;@property (retain) &lt;span style="color: #228b23;"&gt;PMPKVObservation&lt;/span&gt; * &lt;span style="color: #a0522d;"&gt;kvo&lt;/span&gt;;&lt;br /&gt;&lt;span style="color: #7e297f;"&gt;@end&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color: #7e297f;"&gt;@implementation &lt;/span&gt; &lt;span style="color: #228b23;"&gt;PMPKVOTests&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #228b23;"&gt;@synthesize&lt;/span&gt; &lt;span style="color: #228b23;"&gt;kvo&lt;/span&gt; = _kvo;&lt;br /&gt; &lt;br /&gt;- (&lt;span style="color: #228b23;"&gt;void&lt;/span&gt;)&lt;span style="color: #353ff9;"&gt;observationFired&lt;/span&gt;:(&lt;span style="color: #228b23;"&gt;PMPKVObservation&lt;/span&gt; *)&lt;span style="color: #a0522d;"&gt;observation&lt;/span&gt; &lt;span style="color: #353ff9;"&gt;changes&lt;/span&gt;:(&lt;span style="color: #228b23;"&gt;NSDictionary&lt;/span&gt; *)&lt;span style="color: #a0522d;"&gt;changes&lt;/span&gt;;&lt;br /&gt;{&lt;br /&gt;    NSLog(@&lt;span style="color: #8a2452;"&gt;"observation fired for object: %@ keyPath: %@ changes: %@"&lt;/span&gt;,&lt;br /&gt;        observation.observee,&lt;br /&gt;        observation.keyPath,&lt;br /&gt;        changes);&lt;br /&gt;}&lt;br /&gt; &lt;br /&gt;- (&lt;span style="color: #228b23;"&gt;void&lt;/span&gt;)&lt;span style="color: #353ff9;"&gt;selectorObservation&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;&lt;span style="color: #7e297f;"&gt;    self&lt;/span&gt;.kvo = [&lt;span style="color: #228b23;"&gt;PMPKVObservation&lt;/span&gt; observe:anObjectToObserve&lt;br /&gt;                                observer:&lt;span style="color: #7e297f;"&gt;self&lt;/span&gt;&lt;br /&gt;                                selector:&lt;span style="color: #7e297f;"&gt;@selector&lt;/span&gt;(observationFired:changes:)&lt;br /&gt;                                 keyPath:@&lt;span style="color: #8a2452;"&gt;"observeMe"&lt;/span&gt;&lt;br /&gt;                                 options:0];&lt;br /&gt;}&lt;br /&gt; &lt;br /&gt;- (&lt;span style="color: #228b23;"&gt;void&lt;/span&gt;)&lt;span style="color: #353ff9;"&gt;blockObservation&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;&lt;span style="color: #7e297f;"&gt;&lt;/span&gt;&lt;span style="color: #7e297f;"&gt;    self&lt;/span&gt;.kvo = [&lt;span style="color: #228b23;"&gt;PMPKVObservation&lt;/span&gt; observe:anObjectToObserve&lt;br /&gt;                                 keyPath:@&lt;span style="color: #8a2452;"&gt;"observeMe"&lt;/span&gt;&lt;br /&gt;                                 options:0&lt;br /&gt;                                callback:^(&lt;span style="color: #228b23;"&gt;PMPKVObservation&lt;/span&gt; *&lt;span style="color: #a0522d;"&gt;observation&lt;/span&gt;, &lt;span style="color: #228b23;"&gt;NSDictionary&lt;/span&gt; *&lt;span style="color: #a0522d;"&gt;changeDictionary&lt;/span&gt;) {&lt;br /&gt;                                              NSLog(@&lt;span style="color: #8a2452;"&gt;"observation fired for object: %@ keyPath: %@ changes: %@"&lt;/span&gt;,&lt;br /&gt;                                                  observation.observee,&lt;br /&gt;                                                  observation.keyPath,&lt;br /&gt;                                                  changes);&lt;br /&gt;                                 }];&lt;br /&gt;}&lt;br /&gt; &lt;br /&gt;- (&lt;span style="color: #228b23;"&gt;void&lt;/span&gt;)&lt;span style="color: #353ff9;"&gt;dealloc&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;    [ _kvo release];&lt;br /&gt; &lt;br /&gt;    [&lt;span style="color: #7e297f;"&gt;super&lt;/span&gt; dealloc];&lt;br /&gt;}&lt;br /&gt; &lt;br /&gt;&lt;span style="color: #7e297f;"&gt;@end&lt;/span&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;The options and change dictionary are as per normal KVO. You need to be wary of the block causing retain cycles of self as usual.&lt;/p&gt;
&lt;p&gt;Unlike MAKVONotificationCenter and others, you are responsible for managing the lifecycle of the kvo object ? when it is dealloc-ed the observation will be removed. Like MAKVONotificationCenter, a minimum of magic is used to swizzle the dealloc method of the observed object and remove the observation if it still exists (tracked via an associated NSHashTable). If for some reason you want to find out if the kvo object you hold has been released early you can check the isValid accessor (which you can observe with KVO).&lt;/p&gt;
&lt;h3&gt;Caveats&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;While I am using this in a client project, that project has not yet shipped so I can?t promise wide-spread testing. Take a look at the tests in the test app and if you are using scenarios that you don?t thing are tested pull requests are welcome!&lt;/li&gt;
&lt;li&gt;I haven?t tried this under ARC, but I think I?ve made PMPKVObservation.m so it will compile and work as-is (the same can?t be said for the test app). Please let me know how you go.&lt;/li&gt;
&lt;li&gt;No attempt is made to stop you changing the observed object etc. after creation, but doing so isn?t going to be very effective?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Repository:�&lt;a href="https://github.com/aufflick/PMPKVObservation"&gt;https://github.com/aufflick/PMPKVObservation&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=wEJkYy3seWQ:FYcbXgsb5gw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=wEJkYy3seWQ:FYcbXgsb5gw:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?i=wEJkYy3seWQ:FYcbXgsb5gw:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=wEJkYy3seWQ:FYcbXgsb5gw:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?i=wEJkYy3seWQ:FYcbXgsb5gw:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=wEJkYy3seWQ:FYcbXgsb5gw:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?i=wEJkYy3seWQ:FYcbXgsb5gw:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=wEJkYy3seWQ:FYcbXgsb5gw:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MarkAufflicksWeblog/~4/wEJkYy3seWQ" height="1" width="1"/&gt;</description>
<pubDate>Tue, 13 Mar 2012 18:49:13 GMT</pubDate>
<feedburner:origLink>http://mark.aufflick.com/blog/2012/03/13/pmpkvobservation-yet-another-kvo-improvement-project</feedburner:origLink></item>
<item>
<title>Apple Museum</title>
<link>http://feedproxy.google.com/~r/MarkAufflicksWeblog/~3/jizv7sJCm-I/apple-museum</link>
<guid isPermaLink="false">http://mark.aufflick.com/blog/2012/02/22/apple-museum</guid>
<description>After a rejig of my office, there is finally room for the Apple museum. More pieces to come!&lt;p&gt;

&lt;a href="http://www.flickr.com/photos/markaufflick/6775994798/" title="Apple Museum by Mark Aufflick, on Flickr"&gt;&lt;img src="http://farm8.staticflickr.com/7066/6775994798_c08c13b188_b.jpg" width="1024" height="539" alt="Apple Museum"&gt;&lt;/a&gt;&lt;p&gt;

Your eyes don't deceive you, that is a 5 1/4 inch drive - the processor direct slot has an Apple // card in it (which was designed for the LC, which my parents bought it with, but it works great in the Colour Classic).&lt;p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=jizv7sJCm-I:_gd-evpnJ1c:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=jizv7sJCm-I:_gd-evpnJ1c:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?i=jizv7sJCm-I:_gd-evpnJ1c:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=jizv7sJCm-I:_gd-evpnJ1c:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?i=jizv7sJCm-I:_gd-evpnJ1c:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=jizv7sJCm-I:_gd-evpnJ1c:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?i=jizv7sJCm-I:_gd-evpnJ1c:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=jizv7sJCm-I:_gd-evpnJ1c:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MarkAufflicksWeblog/~4/jizv7sJCm-I" height="1" width="1"/&gt;</description>
<pubDate>Wed, 22 Feb 2012 21:10:49 GMT</pubDate>
<feedburner:origLink>http://mark.aufflick.com/blog/2012/02/22/apple-museum</feedburner:origLink></item>
<item>
<title>Emacs Programmed Completion</title>
<link>http://feedproxy.google.com/~r/MarkAufflicksWeblog/~3/tZp46s7EZ6I/emacs-programmed-completion</link>
<guid isPermaLink="false">http://mark.aufflick.com/blog/2012/02/21/emacs-programmed-completion</guid>
<description>&lt;p&gt;Subtitle - how &lt;tt&gt;(completing-read)&lt;/tt&gt; stole my afternoon.&lt;/p&gt;

&lt;p&gt;I thought I'd post my experiences since &lt;tt&gt;completing-read&lt;/tt&gt; is so poorly understood based on the forum and blog posts out there. When you write an interactive Elisp command, many will know that you can easily read a value from the user. Eg: this will ask you how you feel and log it:&lt;/p&gt;

&lt;pre class="sourcebox" style="border-left: 5px solid #ccc; margin-left: 45px; padding-left: 5px; color: #000000; background-color: #ffffff;"&gt;
&lt;span style="color: #696969;"&gt;(&lt;/span&gt;&lt;span style="color: #7f007f;"&gt;defun &lt;/span&gt; &lt;span style="color: #0000ff;"&gt;mood&lt;/span&gt; &lt;span style="color: #696969;"&gt;(&lt;/span&gt;mood&lt;span style="color: #696969;"&gt;)&lt;/span&gt;&lt;br&gt;
  &lt;span style="color: #8b4513;"&gt;"Logs your mood"&lt;/span&gt;&lt;br&gt;
  &lt;span style="color: #696969;"&gt;(&lt;/span&gt;interactive &lt;span style="color: #8b4513;"&gt;"sHow are you feeling? "&lt;/span&gt;&lt;span style="color: #696969;"&gt;)&lt;/span&gt;&lt;br&gt;
  &lt;span style="color: #696969;"&gt;(&lt;/span&gt;message mood&lt;span style="color: #696969;"&gt;))&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;But the string form of argument to &lt;tt&gt;interactive&lt;/tt&gt; is just a shortcut. You can easily supply some code instead, with a static completion list:&lt;/p&gt;

&lt;pre class="sourcebox" style="border-left: 5px solid #ccc; margin-left: 45px; padding-left: 5px; color: #000000; background-color: #ffffff;"&gt;
&lt;span style="color: #696969;"&gt;(&lt;/span&gt;&lt;span style="color: #7f007f;"&gt;defun &lt;/span&gt;  &lt;span style="color: #0000ff;"&gt;mood&lt;/span&gt; &lt;span style="color: #696969;"&gt;(&lt;/span&gt;mood&lt;span style="color: #696969;"&gt;)&lt;/span&gt;&lt;br&gt;
  &lt;span style="color: #8b4513;"&gt;"Logs your mood"&lt;/span&gt;&lt;br&gt;
  &lt;span style="color: #696969;"&gt;(&lt;/span&gt;interactive &lt;span style="color: #696969;"&gt;(&lt;/span&gt;list
                &lt;span style="color: #696969;"&gt;(&lt;/span&gt;completing-read &lt;span style="color: #8b4513;"&gt;"How are you feeling? "&lt;/span&gt; '&lt;span style="color: #696969;"&gt;(&lt;/span&gt;&lt;span style="color: #8b4513;"&gt;"happy"&lt;/span&gt; &lt;span style="color: #8b4513;"&gt;"sad"&lt;/span&gt;&lt;span style="color: #696969;"&gt;)))&lt;/span&gt;&lt;br&gt;
               &lt;span style="color: #696969;"&gt;(&lt;/span&gt;insert arg&lt;span style="color: #696969;"&gt;))&lt;/span&gt;&lt;br&gt;
  &lt;span style="color: #696969;"&gt;(&lt;/span&gt;message mood&lt;span style="color: #696969;"&gt;))&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;If you want something more complex though, instead of supplying a completion list, you can supply a function and that function receives as one of it's arguments the string to be completed. But it's not as simple as that function just returning a list unfortunately, and that's where people come unstuck. Your function is now embedded in the guts of the Emacs completion mechanism and as such it has to answer a whole range of questions about completions. It is &lt;i&gt;reasonably&lt;/i&gt; well documented (if a bit terse) in the &lt;a href="http://www.gnu.org/software/emacs/manual/html_node/elisp/Programmed-Completion.html"&gt;Programmed Completion&lt;/a&gt; section of the Emacs manual. There is a second argument which contains an optional predicate function (I'm ignoring that), but the important bit is the third argument which effectively sets the mode in which your function is being called.&lt;/p&gt;

&lt;p&gt;In fact, your function will usually be called multiple times for each completion tab press. Essentially, your function may be asked to provide the best completion string possible, if there string is an exact match, if there are no matches, or to provide a list of possible matches. There is one final thing that will be asked, and that is the substring your completion is for. So in the example you're about to see I am completing directories, so the completion being offered at any given time only applies to the part after the last forward slash.&lt;/p&gt;

&lt;p&gt;An example is as good as a thousand or so words, so here's my interactive function &lt;tt&gt;cdsrc&lt;/tt&gt;. Basically it's a convenience function to quickly change directory into one of my client projects, which may be one or two levels deep in my main company source directory. The hard work is done by &lt;tt&gt;cdsrc-completions&lt;/tt&gt; and you can see in the &lt;tt&gt;(cond)&lt;/tt&gt; at the end where it responds to the different modes discussed briefly above and in detail in &lt;a href="http://www.gnu.org/software/emacs/manual/html_node/elisp/Programmed-Completion.html"&gt;Programmed Completion&lt;/a&gt;.&lt;/p&gt;

&lt;pre class="sourcebox" style="border-left: 5px solid #ccc; margin-left: 45px; padding-left: 5px; color: #000000; background-color: #ffffff;"&gt;
&lt;span style="color: #696969;"&gt;(&lt;/span&gt;setq cdsrc-completions-prefix &lt;span style="color: #8b4513;"&gt;"~/src/_Pumptheory/"&lt;/span&gt;&lt;span style="color: #696969;"&gt;)&lt;/span&gt;&lt;br&gt;
&lt;br&gt;
&lt;span style="color: #696969;"&gt;(&lt;/span&gt;&lt;span style="color: #7f007f;"&gt;defun &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;safe-fill-common-string-prefix&lt;/span&gt;&lt;span style="color: #696969;"&gt; (&lt;/span&gt;s1 s2&lt;span style="color: #696969;"&gt;)&lt;/span&gt;&lt;br&gt;
&lt;span style="color: #696969;"&gt;  (&lt;/span&gt;&lt;span style="color: #7f007f;"&gt;if&lt;/span&gt;&lt;span style="color: #696969;"&gt; (&lt;/span&gt;and s1 s2&lt;span style="color: #696969;"&gt;)&lt;/span&gt;&lt;br&gt;
&lt;span style="color: #696969;"&gt;      (&lt;/span&gt;fill-common-string-prefix s1 s2&lt;span style="color: #696969;"&gt;)&lt;/span&gt;
    nil&lt;span style="color: #696969;"&gt;))&lt;/span&gt;&lt;br&gt;
&lt;br&gt;
&lt;span style="color: #696969;"&gt;(&lt;/span&gt;&lt;span style="color: #7f007f;"&gt;defun &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;cdsrc-completions&lt;/span&gt;&lt;span style="color: #696969;"&gt; (&lt;/span&gt;str pred mode&lt;span style="color: #696969;"&gt;)&lt;/span&gt;&lt;br&gt;
&lt;span style="color: #696969;"&gt;  (&lt;/span&gt;&lt;span style="color: #7f007f;"&gt;let&lt;/span&gt;&lt;span style="color: #696969;"&gt; ((&lt;/span&gt;dirname&lt;span style="color: #696969;"&gt; (&lt;/span&gt;replace-regexp-in-string &lt;span style="color: #8b4513;"&gt;"[&lt;/span&gt;&lt;span style="color: #8b4513;"&gt;^&lt;/span&gt;&lt;span style="color: #8b4513;"&gt;/]+$"&lt;/span&gt; &lt;span style="color: #8b4513;"&gt;""&lt;/span&gt; str&lt;span style="color: #696969;"&gt;))&lt;/span&gt;&lt;br&gt;
&lt;span style="color: #696969;"&gt;        (&lt;/span&gt;filename&lt;span style="color: #696969;"&gt; (&lt;/span&gt;replace-regexp-in-string &lt;span style="color: #8b4513;"&gt;"^.*/"&lt;/span&gt; &lt;span style="color: #8b4513;"&gt;""&lt;/span&gt; str&lt;span style="color: #696969;"&gt;))&lt;/span&gt;&lt;br&gt;
&lt;span style="color: #696969;"&gt;        (&lt;/span&gt;slashpos&lt;span style="color: #696969;"&gt; (&lt;/span&gt;or&lt;span style="color: #696969;"&gt; (&lt;/span&gt;string-match &lt;span style="color: #8b4513;"&gt;"/.*$"&lt;/span&gt; str&lt;span style="color: #696969;"&gt;)&lt;/span&gt; 0&lt;span style="color: #696969;"&gt;)))&lt;/span&gt;&lt;br&gt;
&lt;br&gt;
&lt;span style="color: #696969;"&gt;    (&lt;/span&gt;&lt;span style="color: #7f007f;"&gt;let&lt;/span&gt;&lt;span style="color: #696969;"&gt; ((&lt;/span&gt;completions&lt;span style="color: #696969;"&gt; (&lt;/span&gt;all-completions filename&lt;span style="color: #696969;"&gt; (&lt;/span&gt;delq nil &lt;br&gt;
&lt;span style="color: #696969;"&gt;                                                  (&lt;/span&gt;mapcar&lt;span style="color: #696969;"&gt; (&lt;/span&gt;&lt;span style="color: #7f007f;"&gt;lambda&lt;/span&gt;&lt;span style="color: #696969;"&gt; (&lt;/span&gt;x&lt;span style="color: #696969;"&gt;)&lt;/span&gt;&lt;br&gt;
&lt;span style="color: #696969;"&gt;                                                            (&lt;/span&gt;and&lt;span style="color: #696969;"&gt; (&lt;/span&gt;file-directory-p&lt;span style="color: #696969;"&gt; (&lt;/span&gt;concat cdsrc-completions-prefix dirname x&lt;span style="color: #696969;"&gt;))&lt;/span&gt;&lt;br&gt;
&lt;span style="color: #696969;"&gt;                                                                 (&lt;/span&gt;not&lt;span style="color: #696969;"&gt; (&lt;/span&gt;string-match &lt;span style="color: #8b4513;"&gt;"^\\."&lt;/span&gt; x&lt;span style="color: #696969;"&gt;))&lt;/span&gt;&lt;br&gt;
&lt;span style="color: #696969;"&gt;                                                                 (&lt;/span&gt;concat x &lt;span style="color: #8b4513;"&gt;"/"&lt;/span&gt;&lt;span style="color: #696969;"&gt;)))&lt;/span&gt;&lt;br&gt;
&lt;span style="color: #696969;"&gt;                                                          (&lt;/span&gt;directory-files&lt;span style="color: #696969;"&gt; (&lt;/span&gt;concat cdsrc-completions-prefix dirname&lt;span style="color: #696969;"&gt;)))))))&lt;/span&gt;&lt;br&gt;
&lt;br&gt;
      &lt;span style="color: #b22222;"&gt;;; &lt;/span&gt;&lt;span style="color: #b22222;"&gt;return differently based on what mode we were called in
&lt;/span&gt;      &lt;span style="color: #b22222;"&gt;;; &lt;/span&gt;&lt;span style="color: #b22222;"&gt;see http://www.gnu.org/software/emacs/manual/html_node/elisp/Programmed-Completion.html&lt;br&gt;
&lt;/span&gt;&lt;span style="color: #696969;"&gt;      (&lt;/span&gt;&lt;span style="color: #7f007f;"&gt;cond&lt;/span&gt;&lt;br&gt;
&lt;span style="color: #696969;"&gt;       ((&lt;/span&gt;not mode&lt;span style="color: #696969;"&gt;)&lt;/span&gt;&lt;span style="color: #696969;"&gt; (&lt;/span&gt;&lt;span style="color: #7f007f;"&gt;cond&lt;/span&gt;&lt;br&gt;
&lt;span style="color: #696969;"&gt;                    ((&lt;/span&gt;and&lt;span style="color: #696969;"&gt; (&lt;/span&gt;eq 0&lt;span style="color: #696969;"&gt; (&lt;/span&gt;length completions&lt;span style="color: #696969;"&gt;))&lt;/span&gt;&lt;span style="color: #696969;"&gt; (&lt;/span&gt;eq 0&lt;span style="color: #696969;"&gt; (&lt;/span&gt;length filename&lt;span style="color: #696969;"&gt;)))&lt;/span&gt;
                     't&lt;span style="color: #696969;"&gt;)&lt;/span&gt; &lt;span style="color: #b22222;"&gt;;; &lt;/span&gt;&lt;span style="color: #b22222;"&gt;in our case, only report exact match when no nested dirs left&lt;br&gt;
&lt;/span&gt;&lt;span style="color: #696969;"&gt;                    ((&lt;/span&gt;&amp;gt;&lt;span style="color: #696969;"&gt; (&lt;/span&gt;length completions&lt;span style="color: #696969;"&gt;)&lt;/span&gt; 1&lt;span style="color: #696969;"&gt;)&lt;/span&gt;&lt;br&gt;
&lt;span style="color: #696969;"&gt;                     (&lt;/span&gt;concat dirname&lt;span style="color: #696969;"&gt; (&lt;/span&gt;or&lt;span style="color: #696969;"&gt; (&lt;/span&gt;reduce 'safe-fill-common-string-prefix completions&lt;span style="color: #696969;"&gt;)&lt;/span&gt; filename&lt;span style="color: #696969;"&gt;)))&lt;/span&gt;&lt;br&gt;
&lt;span style="color: #696969;"&gt;                    ((&lt;/span&gt;eq&lt;span style="color: #696969;"&gt; (&lt;/span&gt;length completions&lt;span style="color: #696969;"&gt;)&lt;/span&gt; 1&lt;span style="color: #696969;"&gt;)&lt;/span&gt;&lt;br&gt;
&lt;span style="color: #696969;"&gt;                     (&lt;/span&gt;concat dirname&lt;span style="color: #696969;"&gt; (&lt;/span&gt;car completions&lt;span style="color: #696969;"&gt;)))&lt;/span&gt;&lt;br&gt;
&lt;span style="color: #696969;"&gt;                    (&lt;/span&gt;'t
                     nil&lt;span style="color: #696969;"&gt;)))&lt;/span&gt;&lt;br&gt;
&lt;br&gt;
&lt;span style="color: #696969;"&gt;       ((&lt;/span&gt;eq mode 't&lt;span style="color: #696969;"&gt;)&lt;/span&gt; completions&lt;span style="color: #696969;"&gt;)&lt;/span&gt;&lt;br&gt;
&lt;br&gt;
&lt;span style="color: #696969;"&gt;       ((&lt;/span&gt;eq mode 'lambda&lt;span style="color: #696969;"&gt;)&lt;/span&gt;&lt;span style="color: #696969;"&gt; (&lt;/span&gt;member&lt;span style="color: #696969;"&gt; (&lt;/span&gt;concat filename &lt;span style="color: #8b4513;"&gt;"/"&lt;/span&gt;&lt;span style="color: #696969;"&gt;)&lt;/span&gt; completions&lt;span style="color: #696969;"&gt;))&lt;/span&gt;&lt;br&gt;
&lt;br&gt;
&lt;span style="color: #696969;"&gt;       (&lt;/span&gt;'t&lt;span style="color: #696969;"&gt; (&lt;/span&gt;cons&lt;span style="color: #696969;"&gt; (&lt;/span&gt;list 'boundaries slashpos&lt;span style="color: #696969;"&gt;)&lt;/span&gt;&lt;span style="color: #696969;"&gt; (&lt;/span&gt;length filename&lt;span style="color: #696969;"&gt;))))&lt;/span&gt; &lt;span style="color: #b22222;"&gt;;; &lt;/span&gt;&lt;span style="color: #b22222;"&gt;let completion know our completions only apply after the last /
&lt;/span&gt;&lt;span style="color: #696969;"&gt;      )))&lt;/span&gt;&lt;br&gt;
&lt;br&gt;
&lt;span style="color: #696969;"&gt;(&lt;/span&gt;&lt;span style="color: #7f007f;"&gt;defun &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;cdsrc&lt;/span&gt;&lt;span style="color: #696969;"&gt; (&lt;/span&gt;path&lt;span style="color: #696969;"&gt;)&lt;/span&gt;&lt;br&gt;
  &lt;span style="color: #8b4513;"&gt;"Changes to a subdir of cdsrc-completions-prefix in the current active interactive shell buffer"&lt;/span&gt;&lt;br&gt;
&lt;span style="color: #696969;"&gt;  (&lt;/span&gt;interactive&lt;span style="color: #696969;"&gt; (&lt;/span&gt;list&lt;br&gt;
&lt;span style="color: #696969;"&gt;                (&lt;/span&gt;&lt;span style="color: #7f007f;"&gt;let&lt;/span&gt;&lt;span style="color: #696969;"&gt; ((&lt;/span&gt;completion-ignore-case 't&lt;span style="color: #696969;"&gt;))&lt;/span&gt;&lt;br&gt;
&lt;span style="color: #696969;"&gt;                  (&lt;/span&gt;completing-read&lt;br&gt;
&lt;span style="color: #696969;"&gt;                   (&lt;/span&gt;concat &lt;span style="color: #8b4513;"&gt;"Enter subdir of "&lt;/span&gt; cdsrc-completions-prefix &lt;span style="color: #8b4513;"&gt;": "&lt;/span&gt;&lt;span style="color: #696969;"&gt;)&lt;/span&gt;&lt;br&gt;
                   'cdsrc-completions&lt;span style="color: #696969;"&gt;))))&lt;/span&gt;&lt;br&gt;
&lt;span style="color: #696969;"&gt;  (&lt;/span&gt;&lt;span style="color: #7f007f;"&gt;let&lt;/span&gt;&lt;span style="color: #696969;"&gt; ((&lt;/span&gt;path2&lt;span style="color: #696969;"&gt; (&lt;/span&gt;concat cdsrc-completions-prefix path&lt;span style="color: #696969;"&gt;)))&lt;/span&gt;&lt;br&gt;
&lt;span style="color: #696969;"&gt;    (&lt;/span&gt;cd path2&lt;span style="color: #696969;"&gt;)&lt;/span&gt;&lt;br&gt;
&lt;span style="color: #696969;"&gt;    (&lt;/span&gt;&lt;span style="color: #7f007f;"&gt;if&lt;/span&gt;&lt;span style="color: #696969;"&gt; (&lt;/span&gt;string-match mode-name &lt;span style="color: #8b4513;"&gt;"Shell"&lt;/span&gt;&lt;span style="color: #696969;"&gt;)&lt;/span&gt;&lt;br&gt;
&lt;span style="color: #696969;"&gt;        (&lt;/span&gt;&lt;span style="color: #7f007f;"&gt;progn&lt;/span&gt;&lt;span style="color: #696969;"&gt; (&lt;/span&gt;end-of-buffer&lt;span style="color: #696969;"&gt;)&lt;/span&gt;&lt;br&gt;
&lt;span style="color: #696969;"&gt;               (&lt;/span&gt;comint-kill-input&lt;span style="color: #696969;"&gt;)&lt;/span&gt;&lt;br&gt;
&lt;span style="color: #696969;"&gt;               (&lt;/span&gt;comint-send-string&lt;span style="color: #696969;"&gt; (&lt;/span&gt;current-buffer&lt;span style="color: #696969;"&gt;)&lt;/span&gt;&lt;span style="color: #696969;"&gt; (&lt;/span&gt;concat &lt;span style="color: #8b4513;"&gt;"cd "&lt;/span&gt; path2&lt;span style="color: #696969;"&gt;))&lt;/span&gt;&lt;br&gt;
&lt;span style="color: #696969;"&gt;               (&lt;/span&gt;comint-send-input&lt;span style="color: #696969;"&gt;)))))&lt;/span&gt;&lt;br&gt;
&lt;/pre&gt;

&lt;p&gt;This is out of my &lt;a href="https://github.com/aufflick/emacs.d"&gt;emacs.d&lt;/a&gt;, specifically &lt;a href="https://github.com/aufflick/emacs.d/blob/master/aufflick-shell-hooks.el"&gt;aufflick-shell-hooks.el&lt;/a&gt;.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=tZp46s7EZ6I:Uy09_m6q1kU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=tZp46s7EZ6I:Uy09_m6q1kU:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?i=tZp46s7EZ6I:Uy09_m6q1kU:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=tZp46s7EZ6I:Uy09_m6q1kU:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?i=tZp46s7EZ6I:Uy09_m6q1kU:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=tZp46s7EZ6I:Uy09_m6q1kU:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?i=tZp46s7EZ6I:Uy09_m6q1kU:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=tZp46s7EZ6I:Uy09_m6q1kU:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MarkAufflicksWeblog/~4/tZp46s7EZ6I" height="1" width="1"/&gt;</description>
<pubDate>Tue, 21 Feb 2012 05:36:05 GMT</pubDate>
<feedburner:origLink>http://mark.aufflick.com/blog/2012/02/21/emacs-programmed-completion</feedburner:origLink></item>
<item>
<title>Comments are broken</title>
<link>http://feedproxy.google.com/~r/MarkAufflicksWeblog/~3/aEpkEbWM_n4/comments-are-broken</link>
<guid isPermaLink="false">http://mark.aufflick.com/blog/2012/02/10/comments-are-broken</guid>
<description>It seems that adding comments is broken after the server move. I'll get right on it...

&lt;b&gt;Update:&lt;/b&gt; Comments are now fixed, both for registered and anonymous persons.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=aEpkEbWM_n4:3dL7Hh461Vo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=aEpkEbWM_n4:3dL7Hh461Vo:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?i=aEpkEbWM_n4:3dL7Hh461Vo:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=aEpkEbWM_n4:3dL7Hh461Vo:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?i=aEpkEbWM_n4:3dL7Hh461Vo:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=aEpkEbWM_n4:3dL7Hh461Vo:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?i=aEpkEbWM_n4:3dL7Hh461Vo:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=aEpkEbWM_n4:3dL7Hh461Vo:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MarkAufflicksWeblog/~4/aEpkEbWM_n4" height="1" width="1"/&gt;</description>
<pubDate>Fri, 10 Feb 2012 01:44:17 GMT</pubDate>
<feedburner:origLink>http://mark.aufflick.com/blog/2012/02/10/comments-are-broken</feedburner:origLink></item>
<item>
<title>New Server</title>
<link>http://feedproxy.google.com/~r/MarkAufflicksWeblog/~3/2iOhdNGoT-Y/new-server</link>
<guid isPermaLink="false">http://mark.aufflick.com/blog/2012/02/09/new-server</guid>
<description>The server that used to host this site, and a few others, has finally had one of it's raid drives fail after over 10 years of use. That's like 100 in server years! At it's age it's time to put it to bed, so I've moved this site over to linode. I upgraded the underlying Postgres, OpenACS and AOLServer instances at the same time.  There are a few styling issues that need fixing, but if you notice anything actually broken please let me know.

BTW, as well as the same hardware running for over 10 years, the same Linux installation (with security patches which eventually had to be backported after it stopped being supported) has been running that whole time. If I remember right, the maximum uptime was around 700 days - just short of two years. Unfortunately it had to be shut down then to move it to another power rail.

I felt a certain nostalgia poking around it's directory structure looking for anything I wanted to keep. It's probably the last server I've had with /usr/local/playground in a nod to &lt;a href="http://twitter.com/randomluser"&gt;russm&lt;/a&gt;. And certainly the last server I will ever run qmail on - it was so awesome, but the massively scalable queue based mail handling just doesn't work with today's spam probes.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=2iOhdNGoT-Y:k56vTY7NkAk:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=2iOhdNGoT-Y:k56vTY7NkAk:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?i=2iOhdNGoT-Y:k56vTY7NkAk:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=2iOhdNGoT-Y:k56vTY7NkAk:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?i=2iOhdNGoT-Y:k56vTY7NkAk:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=2iOhdNGoT-Y:k56vTY7NkAk:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?i=2iOhdNGoT-Y:k56vTY7NkAk:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=2iOhdNGoT-Y:k56vTY7NkAk:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MarkAufflicksWeblog/~4/2iOhdNGoT-Y" height="1" width="1"/&gt;</description>
<pubDate>Thu, 09 Feb 2012 07:09:38 GMT</pubDate>
<feedburner:origLink>http://mark.aufflick.com/blog/2012/02/09/new-server</feedburner:origLink></item>
<item>
<title>Monday Reader?The Adventures of Sherlock Holmes</title>
<link>http://feedproxy.google.com/~r/MarkAufflicksWeblog/~3/4viS8c8uVjo/monday-reader-the-adventures-of-sherlock-holmes</link>
<guid isPermaLink="false">http://mark.aufflick.com/blog/2011/11/13/monday-reader-the-adventures-of-sherlock-holmes</guid>
<description>&lt;div style="float:left; padding-right: 10px;"&gt;&lt;img src="http://g-ecx.images-amazon.com/images/G/01/ciu/d5/52/5e4f225b9da0ed3e501af010.L.jpg"&gt;&lt;/div&gt;

&lt;div&gt;

This week's Monday Reader isn't a technical book, but I'd recommend all developers and support people read all the Sherlock Holmes novels. Not only are the collections of short stories fun and light night time reads, Sir Arthur Conan Doyle has a way of encouraging the reader to be more logical and insightful in his or her thinking:&lt;p&gt;

&lt;blockquote style="font-family: serif;"&gt;&lt;i&gt;To carry the art, however, to its highest pitch, it is necessary that the reasoner should be able to utilise all the facts which have come to his knowledge; and this in itself implies, as you will readily see, a possession of all knowledge, which, even in these days of free education and encyclopaedias, is a somewhat rare accomplishment. It is not so impossible, however, that a man should posses all knowledge which is likely to be useful to him in his work, and this I have endeavoured in my case to do. ? a man should keep his little brain-attic stocked with all the furniture that he is likely to use, and the rest he can put away in the lumbar-room of his library, where he can get it if he wants it.&lt;/i&gt;&lt;/blockquote&gt;

Being out of copyright, you can get these for free in iBooks or elsewhere, but I prefer to read paper books?which I can then put away in the lumbar-room of my library :).&lt;p&gt;

&lt;/div&gt;

&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=4viS8c8uVjo:C6o_U6WIJlg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=4viS8c8uVjo:C6o_U6WIJlg:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?i=4viS8c8uVjo:C6o_U6WIJlg:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=4viS8c8uVjo:C6o_U6WIJlg:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?i=4viS8c8uVjo:C6o_U6WIJlg:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=4viS8c8uVjo:C6o_U6WIJlg:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?i=4viS8c8uVjo:C6o_U6WIJlg:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?a=4viS8c8uVjo:C6o_U6WIJlg:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MarkAufflicksWeblog?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MarkAufflicksWeblog/~4/4viS8c8uVjo" height="1" width="1"/&gt;</description>
<pubDate>Sun, 13 Nov 2011 23:26:22 GMT</pubDate>
<feedburner:origLink>http://mark.aufflick.com/blog/2011/11/13/monday-reader-the-adventures-of-sherlock-holmes</feedburner:origLink></item>
</channel>
</rss>
