<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="http://feeds.aviewfromafar.net/~d/styles/atom10full.xsl" type="text/xsl" media="screen"?><?xml-stylesheet href="http://feeds.aviewfromafar.net/~d/styles/itemcontent.css" type="text/css" media="screen"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-US">
  <title>a view from afar - Home</title>
  <id>tag:aviewfromafar.net,2008:mephisto/</id>
  <generator uri="http://mephistoblog.com" version="0.7.3">Mephisto Noh-Varr</generator>
  
  <link href="http://aviewfromafar.net/" rel="alternate" type="text/html" />
  <updated>2008-06-29T19:07:25Z</updated>
  <link rel="self" href="http://feeds.aviewfromafar.net/aviewfromafar-home" type="application/atom+xml" /><entry xml:base="http://aviewfromafar.net/">
    <author>
      <name>ashleymoran</name>
    </author>
    <id>tag:aviewfromafar.net,2008-06-29:145</id>
    <published>2008-06-29T15:03:00Z</published>
    <updated>2008-06-29T19:07:25Z</updated>
    <category term="Tech" />
    <category term="darcs" />
    <category term="linux" />
    <category term="ubuntu" />
    <link href="http://aviewfromafar.net/2008/6/29/building-darcs-2-0-2-on-ubuntu" rel="alternate" type="text/html" />
    <title>Building darcs 2.0.2 on Ubuntu manually</title>
<summary type="html">&lt;p&gt;Recently had to work with a Ubuntu server and I wanted to get the latest &lt;a href="http://darcs.net"&gt;darcs&lt;/a&gt; working on it.  Simple install guide follows, pending this making it into.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;Recently had to work with a Ubuntu server and I wanted to get the latest &lt;a href="http://darcs.net"&gt;darcs&lt;/a&gt; working on it.  Simple install guide follows, pending this making it into.&lt;/p&gt;
&lt;p&gt;One thing I've learnt in the process is that Ubuntu is &lt;em&gt;very&lt;/em&gt; conservative about its packages - by default, you only get those that were approved at the time of a release, and even if you choose to get updates, they must be specifically ported to your version (I have tried this using 7.10 and 8.04).  In FreeBSD and OS X (MacPorts) land, the ports tree marches on regardless.&lt;/p&gt;

&lt;p&gt;Following are the commands you need.  Apologies if there are some redundant steps on either Ubuntu 7.10 or 8.04, the packages are slightly different as 7.10's package repo contains GHC 6.6, whereas 8.04 has 6.8.  (Again, an annoying frustration I found with Ubuntu.)&lt;/p&gt;

&lt;p&gt;First install the build tools (note some of these are only needed if you wanted to repackage to submit back to the Ubuntu pacakge repo):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    # apt-get install devscripts build-essential wget cdbs \
                   fakeroot liburi-perl debhelper pbuilder dpatch quilt
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then install GHC and all the required Haskell modules:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    # apt-get install ghc6 libghc6-quickcheck-dev libghc6-mtl-dev \
                      libghc6-html-dev libghc6-http-dev libghc6-harp-dev \
                      libghc6-regex-base-dev
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;On 8.04 only (because it uses GHC 6.8) you need the regex-compat library:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    # apt-get install libghc6-regex-compat-dev
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Finally a few libraries that &lt;em&gt;darcs&lt;/em&gt; like to have around:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    # apt-get install zlib1g libcurl3 libcurl4-openssl-dev
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then the usual build procedure (I used --without-docs as this command will be sitting on a server, it saves time and also installing LaTeX packages):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    $ wget http://darcs.net/darcs-2.0.2.tar.gz
    $ tar xf darcs-2.0.2.tar.gz
    $ cd darcs-2.0.2
    $ ./configure --without-docs
    $ make
    # make install
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Final note: You can get the older 2.0.0 release of darcs from  &lt;a href="https://launchpad.net/~laney/+archive"&gt;Iain Lane's personal package archive&lt;/a&gt;.  (I found this after I installed by hand.)&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://aviewfromafar.net/">
    <author>
      <name>ashleymoran</name>
    </author>
    <id>tag:aviewfromafar.net,2008-06-05:124</id>
    <published>2008-06-05T19:45:00Z</published>
    <updated>2008-06-05T19:46:45Z</updated>
    <category term="Tech" />
    <category term="agile" />
    <category term="geekup" />
    <link href="http://aviewfromafar.net/2008/6/5/encouraging-agile-discipline" rel="alternate" type="text/html" />
    <title>GeekUp Sheffield II / Encouraging Agile Discipline</title>
<content type="html">
            &lt;p&gt;Last night I gave my first presentation in the form of the huddle at &lt;a href="http://geekup.org/"&gt;GeekUp Sheffield II&lt;/a&gt;.  A few people asked me for the slides so I've posted them on my blog.  You can grab the PDF version &lt;a href="http://aviewfromafar.net/assets/2008/6/5/encouraging_agile_discipline.pdf"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I think the discussion could have gone on longer.  If anyone wants to bash out some ideas, I hang around on the &lt;a href="http://groups.google.com/group/geekup"&gt;GeekUp mailing list&lt;/a&gt;, or you can email me direct (address on the first slide).&lt;/p&gt;

&lt;p&gt;Many thanks to everyone who attended and spoke at the event, and to Jag for organising it.  It was a great night, and I hope enough people will come forward to speak next month to make it even better.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://aviewfromafar.net/">
    <author>
      <name>ashleymoran</name>
    </author>
    <id>tag:aviewfromafar.net,2008-04-06:112</id>
    <published>2008-04-06T18:38:00Z</published>
    <updated>2008-04-06T18:38:43Z</updated>
    <category term="Tech" />
    <category term="git" />
    <category term="win" />
    <link href="http://aviewfromafar.net/2008/4/6/my-first-adventure-in-github" rel="alternate" type="text/html" />
    <title>My first adventure in github</title>
<content type="html">
            &lt;p&gt;I now have an account on the &lt;a href="http://github.com/"&gt;github&lt;/a&gt; beta - and it's pretty cool.  Since I've only done one thing with it I can only comment on one feature: forking.  It's pretty effortless, and only took me a few minutes to get my &lt;a href="http://github.com/ashleymoran/mailtrap/tree/master"&gt;Mailtrap LogParser extension&lt;/a&gt; up there.  Best thing - assuming they are telling the truth :) - it's easy for the maintainer of the parent repo to merge the changes back in.&lt;/p&gt;

&lt;p&gt;I suspect github will eventually change the nature of open source collaboration.  But where is &lt;a href="http://darcs.net/"&gt;darcshub&lt;/a&gt;?&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://aviewfromafar.net/">
    <author>
      <name>ashleymoran</name>
    </author>
    <id>tag:aviewfromafar.net,2008-04-06:111</id>
    <published>2008-04-06T15:05:00Z</published>
    <updated>2008-04-06T15:06:56Z</updated>
    <category term="Tech" />
    <category term="bdd" />
    <category term="email" />
    <category term="rspec" />
    <category term="ruby" />
    <link href="http://aviewfromafar.net/2008/4/6/a-simple-log-parser-for-mailtrap" rel="alternate" type="text/html" />
    <title>A simple log parser for Mailtrap</title>
<content type="html">
            &lt;p&gt;I just came across a need to test emails sent in a Rails project.  It's a RSpec story integration test I'm working on (using Selenium, not a RailsStory), and using ActionMailer in test mode is not good enough.  Instead I'm using &lt;a href="http://matt.blogs.it/"&gt;Matt Mower&lt;/a&gt;'s handy tool &lt;a href="http://rubymatt.rubyforge.org/mailtrap/"&gt;Mailtrap&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I created a listener class to start and stop mailtrap as the story runs - which is easy enough - but I needed something to parse the log file from Mailtrap.  So I created Mailtrap::LogParser - code available &lt;a href="http://aviewfromafar.net/assets/2008/4/6/mailtrap_log_parser.tgz"&gt;here&lt;/a&gt; for anyone that's interested.&lt;/p&gt;

&lt;p&gt;As soon as &lt;a href="http://github.com"&gt;github&lt;/a&gt; gives me a beta login, I will fork the &lt;a href="http://github.com/mmower/mailtrap/tree/master"&gt;Mailtrap repo&lt;/a&gt; and add this in.  For the mean time, you can use the tarball above.&lt;/p&gt;

&lt;p&gt;This is just a stopgap solution really, until Mailtrap has a way of outputting a more structured (and therefore easily-parseable) output.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://aviewfromafar.net/">
    <author>
      <name>ashleymoran</name>
    </author>
    <id>tag:aviewfromafar.net,2008-04-05:110</id>
    <published>2008-04-05T14:16:00Z</published>
    <updated>2008-04-06T15:07:06Z</updated>
    <category term="Tech" />
    <category term="fail" />
    <category term="snafu" />
    <link href="http://aviewfromafar.net/2008/4/5/probably-going-offline-for-a-bit-soon" rel="alternate" type="text/html" />
    <title>Probably going offline for a bit soon...</title>
<content type="html">
            &lt;p&gt;Thanks to the incredible incompetence of our soon-to-be new broadband provider DST, my blog may be out of action for a while (10 days is apparently the worst case).  DST let the MAC code we provided lapse, and Pipex are refusing to issue a new one.  (Pipex actually claim that issuing a MAC code is considered a form of cancellation, so I'm not even sure why we still have a net connection at all.)&lt;/p&gt;

&lt;p&gt;Unfortunately, due to the time I'm spending at work lately, I don't have time to move the blog to shared hosting.  I intend to do that as soon as I can though... I'm getting &lt;em&gt;ever so slightly&lt;/em&gt; sick of the universal contempt that consumer ISPs show for their customers.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://aviewfromafar.net/">
    <author>
      <name>ashleymoran</name>
    </author>
    <id>tag:aviewfromafar.net,2008-03-24:99</id>
    <published>2008-03-24T16:41:00Z</published>
    <updated>2008-03-24T16:42:15Z</updated>
    <category term="Tech" />
    <category term="mephisto" />
    <category term="win" />
    <link href="http://aviewfromafar.net/2008/3/24/feed-urls-moved-now-using-feedburner-mybrand" rel="alternate" type="text/html" />
    <title>Feed URLs moved - now using FeedBurner MyBrand</title>
<content type="html">
            &lt;p&gt;Since Google bought FeedBurner, their MyBrand feature has been free.  This means you can access FeedBurner feeds via "feeds.&lt;em&gt;yourdomain.com&lt;/em&gt;".  All it takes is a CNAME record in DNS to point &lt;em&gt;feeds.yourdomain.com&lt;/em&gt; to &lt;em&gt;feeds.feedburner.com&lt;/em&gt;, then you can access FeedBurned feeds via a URL you own.  It's pretty generous of Google seeing as it means you can switch feed tracker with a simple DNS change...&lt;/p&gt;

&lt;p&gt;Here is my Apache config (with added line breaks) to send the Mephisto-generated URLs to the FeedBurner ones:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    RewriteEngine on
    RewriteCond %{HTTP_USER_AGENT} !FeedBurner
    RewriteRule ^/feed/atom.xml \
                http://feeds.aviewfromafar.net/aviewfromafar-home \
                [R=301]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Actually the &lt;em&gt;feeds.feedburner.com&lt;/em&gt; addresses haven't moved, so if you are subscribed to this blog via the Atom feed you will still get updates.  But the &lt;em&gt;correct&lt;/em&gt; address is here:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feeds.aviewfromafar.net/aviewfromafar-home"&gt;http://feeds.aviewfromafar.net/aviewfromafar-home&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;...and geeks &lt;em&gt;like being correct&lt;/em&gt;, right? :D&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://aviewfromafar.net/">
    <author>
      <name>ashleymoran</name>
    </author>
    <id>tag:aviewfromafar.net,2008-03-08:89</id>
    <published>2008-03-08T12:11:00Z</published>
    <updated>2008-04-06T15:07:25Z</updated>
    <category term="Tech" />
    <category term="fail" />
    <category term="macosx" />
    <category term="snafu" />
    <link href="http://aviewfromafar.net/2008/3/8/installing-canonscan-on-osx" rel="alternate" type="text/html" />
    <title>Dealing with suckitude - installing a CanoScan LiDE on Mac OS X</title>
<summary type="html">&lt;p&gt;I just bought a CanoScan LiDE 25.  Apparently I'm not the only person that thinks Canon's scanner software is a &lt;a href="http://ann.hates-software.com/2007/04/04/70f1941d.html"&gt;crime against humanity&lt;/a&gt;.  I now use &lt;a href="http://www.yepthat.com/yep/index.html"&gt;Yep&lt;/a&gt; for scanning, so I just need the TWAIN driver provided by the Canon installer.  But the closest I got to making it work was seeing it install the files, then &lt;em&gt;delete them immediately after&lt;/em&gt;.  Yes, that's right.  I WATCHED THE FILES DISAPPEAR from &lt;em&gt;/Library&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I think &lt;a href="http://bart.squarelogic.net/quotes.php"&gt;Bart Simpson&lt;/a&gt; has the best phrase to describe this software - it sucks and blows at the same time.&lt;/p&gt;

&lt;p&gt;My installation guide follows...&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;I just bought a CanoScan LiDE 25.  Apparently I'm not the only person that thinks Canon's scanner software is a &lt;a href="http://ann.hates-software.com/2007/04/04/70f1941d.html"&gt;crime against humanity&lt;/a&gt;.  I now use &lt;a href="http://www.yepthat.com/yep/index.html"&gt;Yep&lt;/a&gt; for scanning, so I just need the TWAIN driver provided by the Canon installer.  But the closest I got to making it work was seeing it install the files, then &lt;em&gt;delete them immediately after&lt;/em&gt;.  Yes, that's right.  I WATCHED THE FILES DISAPPEAR from &lt;em&gt;/Library&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I think &lt;a href="http://bart.squarelogic.net/quotes.php"&gt;Bart Simpson&lt;/a&gt; has the best phrase to describe this software - it sucks and blows at the same time.&lt;/p&gt;

&lt;p&gt;My installation guide follows...&lt;/p&gt;
&lt;p&gt;Basically the trick I used is to extract the file hierarchy manually from the installer.  Download the package from the &lt;a href="http://www.usa.canon.com/consumer/controller?act=ModelInfoAct&amp;amp;amp;fcategoryid=119&amp;amp;amp;modelid=11463#DownloadDetailAct"&gt;CanonScan page&lt;/a&gt;.  Make a folder &lt;em&gt;canon&lt;/em&gt; somewhere in your home folder (I did it on the Desktop).  Drop the installer file in, then run these commands:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    $ cd ~/Desktop/canon
    $ cp ScanGear\ CS\ 11.0\ Eng_Installer.pkg/Contents/Archive.pax.gz .
    $ gunzip Archive.pax.gz
    $ cd /
    $ sudo pax -r -p e -f ~/Desktop/canon/Archive.pax ./Library ./Users
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For those unfamiliar with pax, it's very similar to tar.  The options are: -&lt;em&gt;r&lt;/em&gt; to put it into read mode (to restore from an archive); -&lt;em&gt;p e&lt;/em&gt; to preserve every attribute on the original file; -&lt;em&gt;f&lt;/em&gt; to specify the archive filename; and finally, the list of patterns (paths) to extract from the archive.&lt;/p&gt;

&lt;p&gt;If you extract everything, you'll end up installing a file called &lt;em&gt;CNQL1213_ClassicNotSeize.kext&lt;/em&gt; in &lt;em&gt;/System/Extensions&lt;/em&gt;.  This makes me go pale with fear - the thought of a company that releases software that &lt;em&gt;doesn't let you save scanned images until you quit&lt;/em&gt; installing kernel extensions on my machine just makes me shudder.  It isn't needed to use the TWAIN driver, so I make sure it never goes near my OS.&lt;/p&gt;

&lt;p&gt;If you follow all the instructions above, you should be able to use the CanoScan directly from Yep.  It still launches the Canon interface, but at least you get to save the pages as you scan them. &lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://aviewfromafar.net/">
    <author>
      <name>ashleymoran</name>
    </author>
    <id>tag:aviewfromafar.net,2008-02-21:83</id>
    <published>2008-02-21T14:03:00Z</published>
    <updated>2008-02-21T14:09:43Z</updated>
    <category term="Tech" />
    <category term="fail" />
    <category term="sysadmin" />
    <category term="win" />
    <link href="http://aviewfromafar.net/2008/2/21/well-pingdom-works-at-least" rel="alternate" type="text/html" />
    <title>Well Pingdom works at least</title>
<content type="html">
            &lt;p&gt;I got my first two text messages today - one for this blog and one for &lt;a href="http://www.patchspace.co.uk"&gt;www.patchspace.co.uk&lt;/a&gt;.  I've got the polling resolution set to five minutes and to alert after 30 minutes' downtime, so I was pretty confident it was a power cut (and I was right).  It's the second we've had lately, the last was in the middle of the night, before I subscribed to Pingdom.&lt;/p&gt;

&lt;p&gt;I guess I was wrong in my last post - the real weak spot in my setup is being on a residential power grid.  But then, it's not like I'm not hosting paid-for clients' sites from my home server, so the worst it does it make me look like a fool when nobody can access my blog.&lt;/p&gt;

&lt;p&gt;Next step: buy a UPS.  (A generator seems a bit excessive.)&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://aviewfromafar.net/">
    <author>
      <name>ashleymoran</name>
    </author>
    <id>tag:aviewfromafar.net,2008-02-20:82</id>
    <published>2008-02-20T22:48:00Z</published>
    <updated>2008-03-08T14:01:43Z</updated>
    <category term="Tech" />
    <category term="freebsd" />
    <category term="sysadmin" />
    <link href="http://aviewfromafar.net/2008/2/20/a-bit-about-my-infrastructure" rel="alternate" type="text/html" />
    <title>A few notes about my infrastructure</title>
<summary type="html">&lt;p&gt;As part of starting my own business I've decided it's about time I get some essentials done right - namely backups, uptime monitoring, DNS hosting and email hosting.  I'll also detail some of the other software and hardware I use.  Nothing ground-breaking - but some of these services may be new and/or useful to my readers (24 now!!!).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;UPDATE:&lt;/em&gt; Many Ayromlou wrote a &lt;a href="http://www.nerdlogger.com/2008/03/how-to-setup-easydns-to-work-with.html"&gt;blog post&lt;/a&gt; about setting Google Apps up with easyDNS, which is exactly what I've done. &lt;/p&gt;</summary><content type="html">
            &lt;p&gt;As part of starting my own business I've decided it's about time I get some essentials done right - namely backups, uptime monitoring, DNS hosting and email hosting.  I'll also detail some of the other software and hardware I use.  Nothing ground-breaking - but some of these services may be new and/or useful to my readers (24 now!!!).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;UPDATE:&lt;/em&gt; Many Ayromlou wrote a &lt;a href="http://www.nerdlogger.com/2008/03/how-to-setup-easydns-to-work-with.html"&gt;blog post&lt;/a&gt; about setting Google Apps up with easyDNS, which is exactly what I've done. &lt;/p&gt;
&lt;h2&gt;Backups&lt;/h2&gt;

&lt;p&gt;I tackled this first.  Since I'm running OS X Leopard, &lt;a href="http://www.apple.com/macosx/features/timemachine.html"&gt;Time Machine&lt;/a&gt; is the obvious place to start.  I bought myself a &lt;a href="http://www.lacie.com/uk/products/product.htm?pid=10869"&gt;Lacie Quadra d2 500GB&lt;/a&gt; drive for £99, which is not bad seeing as a bare metal 500GB SATA drive will set you back about £75, and doesn't come with a FireWire 800 port on the back, or a funky flashing blue light on the front.&lt;/p&gt;

&lt;p&gt;I'm actually a little disappointed with Time Machine.  Clearly they pulled the encrypted backup feature but Leopard went gold - which means your backup hard drive is a portable history of your entire life and/or business just waiting to go walkies.  And with no network backup features, you've got no protection against fire, earthquakes or particularly aggressive coffee spills.&lt;/p&gt;

&lt;p&gt;I solved this with an online backup service.   I considered &lt;a href="http://mozy.com/"&gt;Mozy&lt;/a&gt;, but settled on &lt;a href="http://www.jungledisk.com/"&gt;Jungle Disk&lt;/a&gt;.  Jungle Disk seems more committed to openness: their desktop client is truly cross-platform (Win/Mac/Linux are all equal) and they provide sample source for decrypting data in the event they go under.  (Having said that, the client is &lt;em&gt;dog ugly&lt;/em&gt;, but hey, nothing's perfect.)  Also, strictly speaking, Jungle Disk is really a network share - the backup is an extra feature you get from the client software.   So it may turn out useful for document sharing.&lt;/p&gt;

&lt;h2&gt;DNS&lt;/h2&gt;

&lt;p&gt;For outgoing DNS I don't use my ISP's servers - I use &lt;a href="http://www.opendns.com/"&gt;OpenDNS&lt;/a&gt;.  According to their own stats, they have 3 million users and serve 3 billion(!) DNS requests a day.  They don't offer DNS hosting, but when I contacted them they recommended the Canadian company &lt;a href="http://www.easydns.com/"&gt;EasyDNS&lt;/a&gt;, who I now use for &lt;a href="http://www.patchspace.co.uk"&gt;patchspace.co.uk&lt;/a&gt;, my company's domain (this domain to follow, when I get round to it).  EasyDNS is the sort of company the internet needs - their customer service is prompt and helpful, they are actively improving the security of their services, and offer some useful freebies (eg &lt;a href="http://myprivacy.ca"&gt;myprivacy.ca&lt;/a&gt; to help stop WHOIS email harvesting).  They also have a bearable web interface - anyone who has used 123-reg.co.uk will know what I mean.&lt;/p&gt;

&lt;p&gt;EasyDNS let you edit TXT records on each domain, so you can configure &lt;a href="http://support.easydns.com/tutorials/SPF/index.php"&gt;Sender Policy Framework&lt;/a&gt; to help cut down on spam forged from your domains.  SPF is something I only discovered recently, and I'm in the process of applying it to all my domains.&lt;/p&gt;

&lt;h2&gt;Mail&lt;/h2&gt;

&lt;p&gt;For all accounts @patchspace.co.uk I'm using Gmail as part of &lt;a href="http://www.google.com/a/"&gt;Google Apps&lt;/a&gt;.  I avoided Gmail for ages because I hate web interfaces for things I consider desktop apps, but since they rolled out IMAP access I'm hooked.  You can point your DNS MX records to the Google servers - and configure SPF of course - and send and receive everything from your desktop under your own domain.  I use Apple's Mail.app, which takes a bit of configuration to map the sent/received/drafts etc, but afterwards integrates perfectly.   (POP access is supported directly, so hopefully Mail in OS X 10.6 will support Gmail IMAP natively too).  Gmail maps label to IMAP folders, and it respects slashes, so the label "Shops/Amazon/Marketplace" produces a nesting three levels deep.&lt;/p&gt;

&lt;h2&gt;Uptime monitoring&lt;/h2&gt;

&lt;p&gt;I looked at a few (I can't remember which others now) but eventually I settled on &lt;a href="http://www.pingdom.com/"&gt;Pingdom&lt;/a&gt;, a Swedish startup.  For $9.95 a month, the basic package lets you watch 5 sites/servers, with email and text message notifications.  The web interface is a dream to use, and works &lt;em&gt;exactly&lt;/em&gt; how you want it to.  You can configure HTTP and HTTPS requests to check for text strings, handy in case your server is there but actually showing a proxy error.  They have monitoring servers round the world, and let you check as often as every minute.&lt;/p&gt;

&lt;h2&gt;This server&lt;/h2&gt;

&lt;p&gt;This server is actually a desktop machine, running FreeBSD.  It cost about £200, and for that I got a dual-core AMD64 processor, 1GB RAM, and two 80GB SATA drives, which are configured as RAID-1 using &lt;a href="http://www.onlamp.com/pub/a/bsd/2005/11/10/FreeBSD_Basics.html"&gt;gmirror&lt;/a&gt;.  When FreeBSD 7 is released I'd be interested in using &lt;a href="http://ivoras.sharanet.org/freebsd/freebsd7.html"&gt;gjournal&lt;/a&gt;, as the lack of a journalled filesystem in FreeBSD is frustrating.  I'm not yet sure how to configure it alongside gmirror, although the intention of GEOM was to make the modules pluggable, so some combination should work.&lt;/p&gt;

&lt;p&gt;Software wise, the web sites are hosted in or through &lt;a href="http://httpd.apache.org/"&gt;Apache httpd&lt;/a&gt; (this blog uses &lt;a href="http://mongrel.rubyforge.org/"&gt;mongrel&lt;/a&gt; through mod_proxy).  I chose Apache partly by default, even though &lt;a href="http://nginx.net/"&gt;nginx&lt;/a&gt; is pretty trendy right now.  Apache can do pretty much &lt;em&gt;everything&lt;/em&gt;, and I've never had it crash on me (except, that is, when I was meddling at the time...).&lt;/p&gt;

&lt;h2&gt;The rest&lt;/h2&gt;

&lt;p&gt;The only weak spot in my setup is the really crappy SafeCom router that used to crash on me on a weekly basis.  It's been well behaved lately, so I won't rock the boat...&lt;/p&gt;

&lt;p&gt;I was actually surprised how much I ended up using hosted services.  There are some pretty good deals out, and they are really dropping the cost of setting up an IT infrastructure.  Obviously I've only gone through a few solutions here, mainly the critical ones that maintain your minimum bare minimum functioning state (working off a borrowed laptop in an internet café).&lt;/p&gt;

&lt;p&gt;Certainly, out of all the barriers to forming a Web 2 startup or other IT setup, the cost of the supporting technology is pretty much a non-issue these days.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://aviewfromafar.net/">
    <author>
      <name>ashleymoran</name>
    </author>
    <id>tag:aviewfromafar.net,2008-02-05:75</id>
    <published>2008-02-05T22:49:00Z</published>
    <updated>2008-02-06T20:25:05Z</updated>
    <category term="Tech" />
    <category term="fail" />
    <category term="networks" />
    <category term="ruby" />
    <link href="http://aviewfromafar.net/2008/2/5/monitor-your-web-page-load-times-with-ruby" rel="alternate" type="text/html" />
    <title>Tiscali is shit (oh, and monitor your web page load times with Ruby)</title>
<summary type="html">&lt;p&gt;&lt;strong&gt;UPDATE:&lt;/strong&gt; apparently the inconsiderate bastard claiming ownership of my ADSL pipe is, in fact, quite entitled to do so - it's my ISP, Tiscali. Their bandwidth throttling is apparently a bit over-zealous.  &lt;a href="http://www.theregister.co.uk/2008/01/22/tiscali_bandwith_problems_ongoing/"&gt;The Reg&lt;/a&gt; has more details on it - it's unusual of me to not follow their RSS feed but work has kept me busy lately.  Suffice to say I won't be with Tiscali much longer.&lt;/p&gt;

&lt;p&gt;Previous article follows...&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;&lt;strong&gt;UPDATE:&lt;/strong&gt; apparently the inconsiderate bastard claiming ownership of my ADSL pipe is, in fact, quite entitled to do so - it's my ISP, Tiscali. Their bandwidth throttling is apparently a bit over-zealous.  &lt;a href="http://www.theregister.co.uk/2008/01/22/tiscali_bandwith_problems_ongoing/"&gt;The Reg&lt;/a&gt; has more details on it - it's unusual of me to not follow their RSS feed but work has kept me busy lately.  Suffice to say I won't be with Tiscali much longer.&lt;/p&gt;

&lt;p&gt;Previous article follows...&lt;/p&gt;
&lt;p&gt;It's become apparent that some inconsiderate bastard* in my neighbourhood has decided that the entire ADSL pipe for our area belongs to him.  Every evening after about 5 or 6pm, our network grinds to a halt.  At first it's just slow to load pages, but later it starts to take several minutes to access anything.  Then, suddenly, late in the evening, everything returns to normal.&lt;/p&gt;

&lt;p&gt;The ISP support guy (Tiscali, was Pipex) told me today that the second line support is in India, and they have no hesitation in passing the slightest ambiguity back to the UK.  He wouldn't even believe me that it couldn't be a DNS issue with their old servers because &lt;em&gt;I don't use their DNS servers&lt;/em&gt; (I use &lt;a href="http://www.opendns.com"&gt;OpenDNS&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;As part of the diagnostics, I was left collecting speed checks.  Unfortunately, these turn out fine, as it's establishing the connection that is affected.  So I wrote a Ruby script to load &lt;a href="http://www.google.co.uk/"&gt;Google&lt;/a&gt; every 5 minutes for 24 hours.&lt;/p&gt;

&lt;p&gt;* Now I've said that it will probably turn out to be an intermittent technical fault&lt;/p&gt;

&lt;p&gt;Code follows, for anyone that may find it useful...&lt;/p&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;21&lt;tt&gt;
&lt;/tt&gt;22&lt;tt&gt;
&lt;/tt&gt;23&lt;tt&gt;
&lt;/tt&gt;24&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;25&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;26&lt;tt&gt;
&lt;/tt&gt;27&lt;tt&gt;
&lt;/tt&gt;28&lt;tt&gt;
&lt;/tt&gt;29&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;30&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;31&lt;tt&gt;
&lt;/tt&gt;32&lt;tt&gt;
&lt;/tt&gt;33&lt;tt&gt;
&lt;/tt&gt;34&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;35&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;36&lt;tt&gt;
&lt;/tt&gt;37&lt;tt&gt;
&lt;/tt&gt;38&lt;tt&gt;
&lt;/tt&gt;39&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;40&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;41&lt;tt&gt;
&lt;/tt&gt;42&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;require &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;open-uri&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;time&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  start = &lt;span class="co"&gt;Time&lt;/span&gt;.now&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;begin&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;yield&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;rescue&lt;/span&gt; &lt;span class="co"&gt;Timeout&lt;/span&gt;::&lt;span class="co"&gt;Error&lt;/span&gt; =&amp;gt; e&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;return&lt;/span&gt; -(&lt;span class="co"&gt;Time&lt;/span&gt;.now - start)&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;  &lt;span class="co"&gt;Time&lt;/span&gt;.now - start&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;start_time = load_time = &lt;span class="pc"&gt;nil&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="co"&gt;File&lt;/span&gt;.open(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;connection_test.out&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;w&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) &lt;span class="r"&gt;do&lt;/span&gt; |f|&lt;tt&gt;
&lt;/tt&gt;  f.sync = &lt;span class="pc"&gt;true&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;  (&lt;span class="i"&gt;12&lt;/span&gt;*&lt;span class="i"&gt;31&lt;/span&gt;).times &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    start_time = &lt;span class="co"&gt;Time&lt;/span&gt;.now&lt;tt&gt;
&lt;/tt&gt;    time_result = time &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      open(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;http://www.google.co.uk/&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;    load_time, timeout =&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="r"&gt;if&lt;/span&gt; time_result &amp;lt; &lt;span class="i"&gt;0&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        [-time_result, &lt;span class="pc"&gt;true&lt;/span&gt;]&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="r"&gt;else&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        [time_result, &lt;span class="pc"&gt;false&lt;/span&gt;]&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;    output = &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;#{&lt;/span&gt;start_time&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; +&lt;tt&gt;
&lt;/tt&gt;                  &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;#{&lt;/span&gt;timeout ? &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Timeout in&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; : &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Loaded in&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt; &lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; +&lt;tt&gt;
&lt;/tt&gt;                  &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;#{&lt;/span&gt;load_time&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    puts output&lt;tt&gt;
&lt;/tt&gt;    f.puts output&lt;tt&gt;
&lt;/tt&gt;    &lt;tt&gt;
&lt;/tt&gt;    sleep &lt;span class="i"&gt;5&lt;/span&gt;*&lt;span class="i"&gt;60&lt;/span&gt; - load_time&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;It's running now, and it due to finish about 6am Thursday morning...&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://aviewfromafar.net/">
    <author>
      <name>ashleymoran</name>
    </author>
    <id>tag:aviewfromafar.net,2008-01-24:73</id>
    <published>2008-01-24T10:35:00Z</published>
    <updated>2008-01-24T11:05:54Z</updated>
    <category term="Tech" />
    <category term="agile" />
    <category term="socialnetworks" />
    <link href="http://aviewfromafar.net/2008/1/24/vote-for-agile-developers-on-we-vouch-for" rel="alternate" type="text/html" />
    <title>Vote for agile developers on We Vouch For</title>
<summary type="html">&lt;p&gt;I came across this the other day on &lt;a href="http://silkandspinach.net/2008/01/21/we-vouch-for/"&gt;Kevin Rutherford's blog&lt;/a&gt;: a network for agile developers called &lt;a href="http://wevouchfor.org/"&gt;We Vouch For&lt;/a&gt;.  I'm not sure I like the name, but the idea is very worthwhile.  (Think LinkedIn but for agile peer certification.)  This was a topic that came up in the Q&amp;amp;A session at the end of &lt;a href="http://agilenorth.net/"&gt;Agile North 2007&lt;/a&gt;, and it was clear from the amount of discussion that the problem is far from solved.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;I came across this the other day on &lt;a href="http://silkandspinach.net/2008/01/21/we-vouch-for/"&gt;Kevin Rutherford's blog&lt;/a&gt;: a network for agile developers called &lt;a href="http://wevouchfor.org/"&gt;We Vouch For&lt;/a&gt;.  I'm not sure I like the name, but the idea is very worthwhile.  (Think LinkedIn but for agile peer certification.)  This was a topic that came up in the Q&amp;amp;A session at the end of &lt;a href="http://agilenorth.net/"&gt;Agile North 2007&lt;/a&gt;, and it was clear from the amount of discussion that the problem is far from solved.&lt;/p&gt;
&lt;p&gt;I hope the site takes off, because hiring good developers is excruciatingly difficult.  It's quite possible to get a hundred developer CVs and not one that's even &lt;em&gt;heard&lt;/em&gt; of agile (or even something fundamental like automated testing).  In fact, just being able to define TDD would put them in my top 5%, based on CVs I've seen in the past.&lt;/p&gt;

&lt;p&gt;A quick brain-dump of things I think might be good on We Vouch For:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;categorisation of skills, currently it's purely organic&lt;/li&gt;
&lt;li&gt;some use of the certifications to rank developers (I wonder if the Google PageRank algorithm would work?)&lt;/li&gt;
&lt;li&gt;some sort of geographical mapping&lt;/li&gt;
&lt;li&gt;dating certifications (that is in the sense of &lt;em&gt;attaching a date to a certification&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;(possibly) a use of the Apprentice-Journeyman-Master system, although while I like those terms they are difficult to pin down precisely&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I have signed up, but I haven't worked with any of the developers on there so I'm not likely to be certified any time soon :)&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://aviewfromafar.net/">
    <author>
      <name>ashleymoran</name>
    </author>
    <id>tag:aviewfromafar.net,2008-01-19:72</id>
    <published>2008-01-19T17:37:00Z</published>
    <updated>2008-01-19T17:38:27Z</updated>
    <category term="Tech" />
    <category term="mephisto" />
    <link href="http://aviewfromafar.net/2008/1/19/i-blog-with" rel="alternate" type="text/html" />
    <title>I blog with...</title>
<content type="html">
            &lt;p&gt;...&lt;a href="http://mephistoblog.com/"&gt;Mephisto&lt;/a&gt;.  This is my &lt;a href="http://folksr.de/"&gt;folksr.de&lt;/a&gt; vote for the poll &lt;a href="http://folksr.de/votings/what-is-your-favourite-blogging-engine-or-site"&gt;What is your favourite blogging engine or site?&lt;/a&gt;.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://aviewfromafar.net/">
    <author>
      <name>ashleymoran</name>
    </author>
    <id>tag:aviewfromafar.net,2008-01-19:70</id>
    <published>2008-01-19T16:00:00Z</published>
    <updated>2008-01-21T20:04:12Z</updated>
    <category term="Life" />
    <category term="Tech" />
    <category term="gettingthingsdone" />
    <link href="http://aviewfromafar.net/2008/1/19/i-gtd-with-vitalist" rel="alternate" type="text/html" />
    <title>I Get Things Done with...</title>
<content type="html">
            &lt;p&gt;&lt;a href="http://www.vitalist.com/"&gt;Vitalist&lt;/a&gt;.  This is my &lt;a href="http://folksr.de/"&gt;folksr.de&lt;/a&gt; vote for the poll &lt;a href="http://folksr.de/votings/electronic-gtd-system"&gt;What electronic system do you use to Get Things Done?&lt;/a&gt; I just created.&lt;/p&gt;

&lt;p&gt;I've actually tried a few GTD systems to one extent or another, and all of them have advantages and disadvantages.  Vitalist doesn't work perfectly for me, but it does have some really useful features.&lt;/p&gt;

&lt;p&gt;I will probably review the system I use every year or so - I was astonished how many new online systems there are around that I'd never heard about.  You might want to check out the poll and see if it throws up some new ones you haven't seen (I didn't label which ones are web and which are desktop, though).&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://aviewfromafar.net/">
    <author>
      <name>ashleymoran</name>
    </author>
    <id>tag:aviewfromafar.net,2008-01-19:66</id>
    <published>2008-01-19T13:53:00Z</published>
    <updated>2008-01-19T17:36:59Z</updated>
    <category term="Tech" />
    <category term="activerecord" />
    <category term="databases" />
    <category term="rails" />
    <link href="http://aviewfromafar.net/2008/1/19/class-table-inheritance-in-activerecord" rel="alternate" type="text/html" />
    <title>[OLD] Class-table inheritance in ActiveRecord</title>
<summary type="html">&lt;p&gt;This article is nothing new.  I first published it on November 7th, 2006.  The site it went up on is no longer running, but it seemed a shame to let it disappear.  I imagine the ActiveRecord codebase has moved on significantly enough that the patch would be very difficult to apply now.&lt;/p&gt;

&lt;p&gt;There were quite a few comments to the original post (not preserved here) expressing interest in CTI.  Unfortunately, there were none from any of the ActiveRecord team, but then, DHH &lt;a href="http://trak3r.blogspot.com/2006/06/should-we-drink-dhhs-kool-aid.html"&gt;doesn't even like foreign keys&lt;/a&gt;, so expecting interest in CTI would be downright naive.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;This article is nothing new.  I first published it on November 7th, 2006.  The site it went up on is no longer running, but it seemed a shame to let it disappear.  I imagine the ActiveRecord codebase has moved on significantly enough that the patch would be very difficult to apply now.&lt;/p&gt;

&lt;p&gt;There were quite a few comments to the original post (not preserved here) expressing interest in CTI.  Unfortunately, there were none from any of the ActiveRecord team, but then, DHH &lt;a href="http://trak3r.blogspot.com/2006/06/should-we-drink-dhhs-kool-aid.html"&gt;doesn't even like foreign keys&lt;/a&gt;, so expecting interest in CTI would be downright naive.&lt;/p&gt;
&lt;h2&gt;The original article&lt;/h2&gt;

&lt;p&gt;I'm pretty fanatical about making sure databases are correct and unambiguous.  Unfortunately, &lt;a href="http://www.martinfowler.com/eaaCatalog/singleTableInheritance.html"&gt;single-table inheritance&lt;/a&gt; makes this hard, as you have to store attributes about distinct types of entities together in one table.  To me, &lt;a href="http://www.martinfowler.com/eaaCatalog/classTableInheritance.html"&gt;class-table inheritance&lt;/a&gt; is the correct way to record information when you have an entity type hierarchy in your database (and therefore a class hierarchy in your application).&lt;/p&gt;

&lt;h2&gt;About the implementation&lt;/h2&gt;

&lt;h3&gt;Normalised data&lt;/h3&gt;

&lt;p&gt;I started by solving the relatively simple problem of reading and writing attributes in satellite tables.  This is useful in itself for various reasons I won't bore you with now, but it's an essential part of the CTI implementation. &lt;/p&gt;

&lt;p&gt;There's a new &lt;code&gt;normalized_data_test.rb&lt;/code&gt; file in the tests that shows how this works.  It consists of two class level methods in ActiveRecord::Base, &lt;code&gt;normalized_attribute&lt;/code&gt; and &lt;code&gt;normalized_attribute_group&lt;/code&gt;.  Columns of the satellite table appear to your application to be in the model table itself.&lt;/p&gt;

&lt;h3&gt;Reading the class-tables&lt;/h3&gt;

&lt;p&gt;I've tried to make CTI work as transparently as STI.  Given these tables...&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;CREATE TABLE people (
  id serial PRIMARY KEY,
  first_name varchar,
  last_name varchar
);

CREATE TABLE employees (
  person_id integer NOT NULL REFERENCES people (id),
  salary decimal(10,2),
  hired_at timestamp
);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and these classes...&lt;/p&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;Person&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;ActiveRecord&lt;/span&gt;::&lt;span class="co"&gt;Base&lt;/span&gt;; &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;Employee&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;Person&lt;/span&gt;; &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;then ActiveRecord will follow this procedure (or something evquivalent, as the algorithm has to rerun when classes are reconfigured) to initialise inheritance:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;check the &lt;em&gt;people&lt;/em&gt; table exists&lt;/li&gt;
&lt;li&gt;check for a &lt;em&gt;type&lt;/em&gt; column in &lt;em&gt;people&lt;/em&gt;
&lt;ul&gt;
&lt;li&gt;if it does - use STI and stop here&lt;/li&gt;
&lt;li&gt;if not - assume CTI&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;check the &lt;em&gt;employees&lt;/em&gt; table exists&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The convention is that the primary key in each table is named after the immediate supertype. To add a  &lt;em&gt;Manager&lt;/em&gt; subtype to the above example:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;CREATE TABLE managers (
  employee_id integer NOT NULL REFERENCES employees (employee_id),
  has_pointy_hair boolean
);
&lt;/code&gt;&lt;/pre&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;Manager&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;Employee&lt;/span&gt;; &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;h3&gt;Manual overrides&lt;/h3&gt;

&lt;p&gt;If you are working with a legacy schema, you can override the table name and the primary key (which is actually a &lt;em&gt;foreign&lt;/em&gt; key but I wanted to re-use the method name).&lt;/p&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;Customer&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;ActiveRecord&lt;/span&gt;::&lt;span class="co"&gt;Base&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  set_table_name &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;suckers&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  set_primary_key &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;sucker_id&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;h2&gt;Mixing inheritance types&lt;/h2&gt;

&lt;p&gt;I've tried to make CTI integrate as seamlessly as possibly with STI.  You can use both in the same inheritance chain, as long as STI is at the &lt;em&gt;end&lt;/em&gt;.  For example, to extend the example above:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ALTER TABLE managers ADD COLUMN type varchar;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can then do:&lt;/p&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;ImportantManager&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;Manager&lt;/span&gt;; &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;There are three reasons I didn't attempt to make STI work in the middle of an inheritance chain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it would massively complicate the algorithm that determines the class type&lt;/li&gt;
&lt;li&gt;it would mean maintaining the inheritance column ("type") to store names of classes that actually have their own table, potentially an integrity nightmare (not to mention the fact you could potentially have multiple blocks of STI in an inheritance chain)&lt;/li&gt;
&lt;li&gt;I don't imagine anyone would actually want to do it (if you want to switch from STI to CTI, refactor your database!)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;What's left to do&lt;/h2&gt;

&lt;p&gt;There are a few minor things, mainly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Currently CTI objects let you call attribute accessors that should only exist in subclasses, but I'll fix that soon.&lt;/li&gt;
&lt;li&gt;I need to test that the mixed inheritance types work as described above.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I've tested that CTI works on its own.  I've tested that everything (well, except for &lt;a href="http://groups-beta.google.com/group/rubyonrails-core/browse_thread/thread/c8c45df5f9870cea"&gt;one thing&lt;/a&gt;) that used to work in ActiveRecord still works with CTI in place, just not using it.  However... I &lt;em&gt;haven't&lt;/em&gt; tested that all the existing ActiveRecord features work with CTI classes.  The reason is that this could potentially involve duplicating most of the existing unit tests, and I want to get some feedback from the Rails community first.  I imagine the associations still need some major work.&lt;/p&gt;

&lt;p&gt;The patch is available here: [http://dev.rubyonrails.org/ticket/6566]&lt;/p&gt;

&lt;p&gt;Feel free to leave feedback&lt;/p&gt;

&lt;h2&gt;Links&lt;/h2&gt;

&lt;p&gt;I've had a search on the interweb and these are the most interesting articles about CTI in Rails:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.agilewebdevelopment.com/plugins/inherits_from"&gt;www.agilewebdevelopment.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://johnwilger.com/articles/2005/09/29/class-table-inheritance-in-rails-with-postgresql"&gt;johnwilger.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://wrath.rubyonrails.org/pipermail/rails-core/2006-August/002226.html"&gt;wrath.rubyonrails.org&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
          </content>  </entry>
  <entry xml:base="http://aviewfromafar.net/">
    <author>
      <name>ashleymoran</name>
    </author>
    <id>tag:aviewfromafar.net,2007-12-28:57</id>
    <published>2007-12-28T00:20:00Z</published>
    <updated>2007-12-28T00:21:50Z</updated>
    <category term="Life" />
    <category term="spam" />
    <link href="http://aviewfromafar.net/2007/12/28/how-ironic-can-an-unsubscribe-email-be" rel="alternate" type="text/html" />
    <title>How ironic can an unsubscribe email be?</title>
<summary type="html">&lt;p&gt;I have recently been sick to death of PacificPoker.com emails.  After clicking the unsubscribe link in their spam^H^H^H^H newsletter for the fifty thousandth time, I can say - without hyperbole - that I was not very happy.  My festive spirit somewhat dampened by yet another promise of a chance at the $75m dream ticket, I sent them this rather terse email:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    Subject:    TAKE ME OFF YOUR MAILING LIST
    From:       &amp;lt;my address removed for spam prevention&amp;gt;
    Date:       December 27, 2007 11:50:19 am GMT
    To:         support@pacificpoker.com

    I have lost count of the number of times I have tried to
    unsubscribe.  Please remove me IMMEDIATELY
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Their reply is priceless...&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;I have recently been sick to death of PacificPoker.com emails.  After clicking the unsubscribe link in their spam^H^H^H^H newsletter for the fifty thousandth time, I can say - without hyperbole - that I was not very happy.  My festive spirit somewhat dampened by yet another promise of a chance at the $75m dream ticket, I sent them this rather terse email:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    Subject:    TAKE ME OFF YOUR MAILING LIST
    From:       &amp;lt;my address removed for spam prevention&amp;gt;
    Date:       December 27, 2007 11:50:19 am GMT
    To:         support@pacificpoker.com

    I have lost count of the number of times I have tried to
    unsubscribe.  Please remove me IMMEDIATELY
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Their reply is priceless...&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    From:        support@pacificpoker.com
    Subject:     Re: [R] TAKE ME OFF YOUR MAILING LIST
    Date:        December 27, 2007 3:40:33 pm GMT
    To:           &amp;lt;my address removed for spam prevention&amp;gt;

    Dear Ashley,

    Thank you for contacting 888.

    Ashley, we would like to inform you that we have
    removed you from the mailing list.

    We apologize for any inconvenience our advertisements
    may have caused you, as it is certainly not our
    intention to offend or upset anyone.

    Ashley, Check out the ?$80,000? tab in Pacific Poker to
    find out how to play for your share of at least $80,000
    every Sunday at 15:30 PPT! Buy into the Qualifier for
    only $88 + $8, play a Micro-Satellite for as little as
    50¢ or win your seat for free from a Freeroll
    tournament.

    Thank you for being a member of 888 and for the
    confidence you have placed in us. Please contact us
    whenever we can be of further service.

    Kind regards,
    &amp;lt;Some Hispanic-Named Support Guy&amp;gt;
    Member Support Representative
    support@pacificpoker.com
    www.888.com
    **********************************************************
    Get $150 just by inviting a friend to Pacific Poker! And
    your friend will get $50! It's so easy! For details,
    visit www.pacificpoker.com and click on the INVITE A
    FRIEND icon.
    NOTE: *Exceptions apply according to country of registration.
&lt;/code&gt;&lt;/pre&gt;
          </content>  </entry>
</feed>
