<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>yob.id.au</title>
    <link>http://yob.id.au/</link>
    <description>yob.id.au - James Healy</description>
  
    <item>
      <title>New Zealand as Australia's Data Centre?</title>
      <link>http://yob.id.au/2012/01/08/new-zealand-as-australias-datacentre.html</link>
      <guid>http://yob.id.au/2012/01/08/new-zealand-as-australias-datacentre</guid>
      <pubDate>Sun, 08 Jan 2012 00:00:00 +1100</pubDate>
      <description>&lt;p&gt;Like many rubyists I&amp;#8217;ve often used &lt;a href='http://www.slicehost.com'&gt;Slicehost&lt;/a&gt; to host my virtual servers.&lt;/p&gt;

&lt;p&gt;As a networking nerd who cares about latency (see &lt;a href='http://rescomp.stanford.edu/~cheshire/rants/Latency.html'&gt;It&amp;#8217;s the Latency Stupid&lt;/a&gt; ) I&amp;#8217;ve always wanted to host my client sites in Australia, however data prices here made it prohibitively expensive. Slicehost in the States was often the next best option.&lt;/p&gt;

&lt;p&gt;Some time ago they were purchased by &lt;a href='http://www.rackspace.com'&gt;Rackspace&lt;/a&gt; and they&amp;#8217;re finally preparing to migrate everyone to the Rackspace cloud platform.&lt;/p&gt;

&lt;p&gt;I was happy enough with the migration, however it prompted me to do a quick scan of other options and I found something surprising. I can run a VPS at &lt;a href='http://rimuosting.com'&gt;Rimuhosting&amp;#8217;s&lt;/a&gt; Auckland data centre for about the same price as their US datacentre and it&amp;#8217;s only a 50ms RTT from Melbourne.&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s not unusual to find data costs with Australian VPS providers (including Rimu) hovering around AUD$2/Gb. At rimuhosting&amp;#8217;s Auckland datacentre it&amp;#8217;s NZD$0.20/Gb (currently about AUD$0.15).&lt;/p&gt;

&lt;p&gt;What&amp;#8217;s going on here? Are data prices in New Zealand cheaper than Australia? Is Rimuhosting oversubscribing their transit links? Are they buying budget transit? Are other New Zealand companies cheaper than their Australian competitors or is this an edge case?&lt;/p&gt;

&lt;p&gt;Whatever the reason, I moved a clients VPS from the US to Auckland two weeks ago and couldn&amp;#8217;t be happier with the result.&lt;/p&gt;</description>
    </item>
  
    <item>
      <title>Preflight In Ruby</title>
      <link>http://yob.id.au/2011/07/29/preflight-in-ruby.html</link>
      <guid>http://yob.id.au/2011/07/29/preflight-in-ruby</guid>
      <pubDate>Fri, 29 Jul 2011 00:00:00 +1000</pubDate>
      <description>&lt;p&gt;The &lt;a href='http://www.adobe.com/devnet/pdf/pdf_reference.html'&gt;PDF spec&lt;/a&gt; is a beast. Amongst a long list of features it allows transparencies, embedding of flash, video and javascript, content encryption and multiple colour spaces.&lt;/p&gt;

&lt;p&gt;Such features have their place, but sometimes you just need to say no. Standards like &lt;a href='http://en.wikipedia.org/wiki/PDF/A'&gt;PDF/A&lt;/a&gt; and &lt;a href='http://en.wikipedia.org/wiki/PDF/X'&gt;PDF/X&lt;/a&gt; are subsets of the full PDF spec that target particular use cases like archiving or printing.&lt;/p&gt;

&lt;p&gt;To check a given PDF conforms to a required standard you run a preflight check. There are expensive programs that can preflight, but they&amp;#8217;re &amp;#8230;.. expensive, and generally hard to script.&lt;/p&gt;

&lt;p&gt;I recently released the &lt;a href='http://rubygems.org/gems/preflight'&gt;preflight&lt;/a&gt; rubygem for performing preflight checks from ruby. It&amp;#8217;s not as full featured as the commercial options, but it&amp;#8217;s free and may solve 80% of your problem.&lt;/p&gt;

&lt;p&gt;Start by installing the gem&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;    gem install preflight
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;To check a file passes a PDF/X-1a preflight it&amp;#8217;s just three lines.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;    &lt;span class='nb'&gt;require&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;preflight&amp;#39;&lt;/span&gt;

    &lt;span class='n'&gt;preflight&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;Preflight&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Profiles&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;PDFX1A&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;

    &lt;span class='nb'&gt;puts&lt;/span&gt; &lt;span class='n'&gt;preflight&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;check&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;somefile.pdf&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;inspect&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;If you need more control over the profile, you can build your own profile.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;    &lt;span class='nb'&gt;require&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;preflight&amp;quot;&lt;/span&gt;

    &lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;MyPreflight&lt;/span&gt;
      &lt;span class='kp'&gt;include&lt;/span&gt; &lt;span class='no'&gt;Preflight&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Profile&lt;/span&gt;

      &lt;span class='n'&gt;rule&lt;/span&gt; &lt;span class='no'&gt;Preflight&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Rules&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;MaxVersion&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='mi'&gt;4&lt;/span&gt;
      &lt;span class='n'&gt;rule&lt;/span&gt; &lt;span class='no'&gt;Preflight&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Rules&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;DocumentId&lt;/span&gt;
      &lt;span class='n'&gt;rule&lt;/span&gt; &lt;span class='no'&gt;Preflight&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Rules&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;OnlyEmbeddedFonts&lt;/span&gt;
      &lt;span class='n'&gt;rule&lt;/span&gt; &lt;span class='no'&gt;Preflight&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Rules&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;MinPpi&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;300&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;

    &lt;span class='n'&gt;preflight&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;MyPreflight&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;

    &lt;span class='nb'&gt;puts&lt;/span&gt; &lt;span class='n'&gt;preflight&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;check&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;somefile.pdf&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;inspect&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;For a list of available rules, check out the classes in the Preflight::Rules namespace - each class has documentation describing how to use it in a profile.&lt;/p&gt;

&lt;p&gt;If the provided rules don&amp;#8217;t cover everything you need, you can also write your own.&lt;/p&gt;

&lt;p&gt;For more details and examples, check out project on &lt;a href='https://github.com/yob/pdf-preflight'&gt;github&lt;/a&gt;.&lt;/p&gt;</description>
    </item>
  
    <item>
      <title>Ethical Superation Followup</title>
      <link>http://yob.id.au/2011/07/24/ethical-superation-followup.html</link>
      <guid>http://yob.id.au/2011/07/24/ethical-superation-followup</guid>
      <pubDate>Sun, 24 Jul 2011 00:00:00 +1000</pubDate>
      <description>&lt;p&gt;Some time ago I got angry with my faux-ethical superannuation and &lt;a href='/2010/01/16/ethical-superannuation.html'&gt;did some research on alternatives&lt;/a&gt;. Then I put off making a decision for 18 months. I excel at delaying hard decisions, and comparing Super funds is definitely hard.&lt;/p&gt;

&lt;p&gt;This week I finally decided I needed to do something about it. I&amp;#8217;m pessimistic about the short term prospects for global markets anyway, so I&amp;#8217;ve decided to simultaneously lower my risk profile and move my superannuation to &lt;a href='http://www.austethical.com.au/'&gt;Australian Ethical&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Super company documentation makes comparing returns almost impossible, but I&amp;#8217;m confident I&amp;#8217;ll get returns I&amp;#8217;m happy with whilst avoiding companies making money in unethical and unsustainable ways.&lt;/p&gt;</description>
    </item>
  
    <item>
      <title>Db2fog</title>
      <link>http://yob.id.au/2011/07/23/db2fog.html</link>
      <guid>http://yob.id.au/2011/07/23/db2fog</guid>
      <pubDate>Sat, 23 Jul 2011 00:00:00 +1000</pubDate>
      <description>&lt;p&gt;Several years ago &lt;a href='http://rhnh.net/'&gt;Xavier Shay&lt;/a&gt; published his &lt;a href='http://rubygems.org/gems/db2s3'&gt;db2s3&lt;/a&gt; gem for backing up the database from your rails project to Amazon S3.&lt;/p&gt;

&lt;p&gt;Xavier&amp;#8217;s original code depended on the &lt;a href='http://rubygems.org/gems/aws-s3'&gt;aws-s3&lt;/a&gt; gem. aws-s3 works well enough, however it appears to be unmaintained and has a few rough edges. In particular, it doesn&amp;#8217;t cleanly handle S3 regions outside US-east. It also uses class variables for configuration, making it difficult to authenticate with alternate accounts at other points in my application.&lt;/p&gt;

&lt;p&gt;The solution to these issues was to switch the dependency from aws-s3 to &lt;a href='http://rubygems.org/gems/fog'&gt;fog&lt;/a&gt;, a newer gem that is actively maintained. As a bonus, it also brings us support for additional storage providers like &lt;a href='http://www.rackspace.com/cloud/cloud_hosting_products/files/'&gt;Rackspace cloudfiles&lt;/a&gt; and &lt;a href='http://ninefold.com/'&gt;Ninefold&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After &lt;a href='https://twitter.com/#!/jim_healy/status/93910235277836288'&gt;checking with Xavier&lt;/a&gt; I&amp;#8217;ve forked his code and released a new gem - &lt;a href='http://rubygems.org/gems/db2fog'&gt;db2fog&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To use it, start by adding it to the Gemfile in your rails app:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;    gem &lt;span class='s1'&gt;&amp;#39;db2fog&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Then configure it by putting this in config/initializers/db2fog.rb:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;    &lt;span class='no'&gt;DB2Fog&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;config&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
      &lt;span class='ss'&gt;:aws_access_key_id&lt;/span&gt;     &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;yourkey&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
      &lt;span class='ss'&gt;:aws_secret_access_key&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;yoursecretkey&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
      &lt;span class='ss'&gt;:directory&lt;/span&gt;             &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;bucket-name&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
      &lt;span class='ss'&gt;:provider&lt;/span&gt;              &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;AWS&amp;#39;&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Now use the rake tasks to perform backups and restores. Run them manually first, then add them to cron for automatic backups. I recommend running a few backup every few hours and the clean task daily.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;    rake db2fog:backup:full  &lt;span class='nv'&gt;RAILS_ENV&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;production
    rake db2fog:backup:clean &lt;span class='nv'&gt;RAILS_ENV&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;production
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;That&amp;#8217;s it! A dead simple way to get offsite backups that will probably cost you only cents per month. For details and examples for configuring sotrage providers like Rackspace check the &lt;a href='https://github.com/yob/db2fog'&gt;project README&lt;/a&gt; on github.&lt;/p&gt;</description>
    </item>
  
    <item>
      <title>Scan Like A Pro</title>
      <link>http://yob.id.au/2010/09/28/scan-like-a-pro.html</link>
      <guid>http://yob.id.au/2010/09/28/scan-like-a-pro</guid>
      <pubDate>Tue, 28 Sep 2010 00:00:00 +1000</pubDate>
      <description>&lt;p&gt;Several years ago I read an &lt;a href='http://onlamp.com/pub/a/onlamp/2006/11/02/personal_document_management.html'&gt;article&lt;/a&gt; on scanning personal paperwork and reducing physical clutter. I liked the concept (except the part about using perforce!) and have since refined my own workflow to achieve something similar.&lt;/p&gt;

&lt;p&gt;These days I scan and OCR nearly all paperwork I deal with (bills, contracts, letters, statements, etc), store them in a shallow directory structure and commit them to a git repository.&lt;/p&gt;

&lt;h2 id='step_one_scanner'&gt;Step One: Scanner&lt;/h2&gt;

&lt;p&gt;For scanning, I use a document scanner at a clients office. I&amp;#8217;m there a couple of days a week, so every now and again I take a pile of paper in and feed it through. They have a &lt;a href='http://www.support.xerox.com/SRVS/CGI-BIN/WEBCGI.EXE?New,Kb=x_WC7245_en,Company={683D76C8-B5C5-416E-9754-DD015FDB4F2E},ts=x_main_en,ques=ref%28Country%29:str%28AUS%29,ques=ref%28Prod_WC7228_WC7235_WC7245%29:str%28DC_C2200_C3300%29,question=ref%28ProdFamily%29:str%28Prod_WC7228_WC7235_WC7245%29,varset=Xcntry:AUS,varset=Xlang:en_AU,varset=prodID:DC_C2200_C3300,varset=prodName:DocuCentre-II%20C2200/C3300'&gt;Xerox DocuCentre-II C2200&lt;/a&gt; - it can scan 75 double sided pages at a time and saves PDFs to a windows share. Depending on the document, I scan in colour or greyscale at 600 dpi - the saved files are larger, but I deal with that later.&lt;/p&gt;

&lt;h2 id='step_two_ocr'&gt;Step Two: OCR&lt;/h2&gt;

&lt;p&gt;The resulting PDFs have a single scanned image per page - I really wanted to OCR them if possible and make the content searchable. I explored various open source options that could run on my Linux systems, but none worked as well as I hoped. They generally had accuracy issues or would only output the recognised characters to a text file.&lt;/p&gt;

&lt;p&gt;A few years ago I was working at a University, so I splashed out on an academic copy of Adobe Acrobat Pro 9.0 for Windows. Dual booting is a pain, but the OCR support is second to none and makes the hassle worthwhile.&lt;/p&gt;

&lt;p&gt;Version 9.0 or later of Acrobat Pro has an OCR feature called ClearScan. After recognising the characters on each page, it converts them to a custom vector font and &lt;em&gt;replaces&lt;/em&gt; the scanned image of that character with the vector character. This makes the text indexable by standard PDF search tools (like spotlight, etc) and has a massive impact on the file size. A 24 page text-only document I scanned last week went from 11Mb to 700Kb.&lt;/p&gt;

&lt;p&gt;To use ClearScan open the scanned PDF Acrobat, select the Document menu, then choose &amp;#8220;OCR Text Recognition&amp;#8221; and &amp;#8220;Recognise text using OCR&amp;#8221;. Check the settings in the window that pops up and use the edit button to ensure &amp;#8220;PDF output style&amp;#8221; is set to Clearscan and &amp;#8220;Downsample&amp;#8221; is set to Lowest (600 dpi).&lt;/p&gt;

&lt;h2 id='step_three_git'&gt;Step Three: Git&lt;/h2&gt;

&lt;p&gt;As a final step I store the files in a simple directory structure and save them to a git repository. A version control system might seem a bit odd, as the files generally don&amp;#8217;t change much (if at all) but git makes it easy to store a backup of all the files on my server.&lt;/p&gt;

&lt;p&gt;I group the documents by type and year. Anything more complex is unnecessary as I usually find what I need by searching. Here&amp;#8217;s a sample of the directory structure:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='text'&gt;    banking/2010/20100630 - statement.pdf
    banking/2010/20100720 - letter.pdf
    banking/2010/20100731 - statement.pdf
    insurance/2009/20090317 - contents renewal.pdf
    insurance/2010/20100315 - contents renewal.pdf
    receipts/2010/20100915 - laptop.pdf
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id='step_four_profit'&gt;Step Four: Profit&lt;/h2&gt;

&lt;p&gt;It has proven to be incredibly useful to have all my documents scanned and searchable. Not only is there less stuff floating around my house, but looking up records has become a trivial task.&lt;/p&gt;

&lt;p&gt;I regularly look for files to send to my accountant and to check when I can expect a new bill to arrive. Recently I also had to look up receipts as part of an insurance claim.&lt;/p&gt;

&lt;p&gt;Now that I have a standard workflow setup, the whole process is relatively little work and the results are convenient.&lt;/p&gt;</description>
    </item>
  
    <item>
      <title>Extending Formtastic</title>
      <link>http://yob.id.au/2010/08/19/extending-formtastic.html</link>
      <guid>http://yob.id.au/2010/08/19/extending-formtastic</guid>
      <pubDate>Thu, 19 Aug 2010 00:00:00 +1000</pubDate>
      <description>&lt;p&gt;&lt;a href='http://github.com/justinfrench/formtastic'&gt;Formtastic&lt;/a&gt; is a great little gem for cleaning up form code in your Rails view. It provides a neat DSL for building forms and outputs semantic markup with plenty of hooks for you to style with.&lt;/p&gt;

&lt;p&gt;The project readme has extensive samples, but here&amp;#8217;s what a simple form might look like:&lt;/p&gt;

&lt;p&gt;&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='erb'&gt;&lt;span class='x'&gt;    &lt;/span&gt;&lt;span class='cp'&gt;&amp;lt;%&lt;/span&gt; &lt;span class='n'&gt;semantic_form_for&lt;/span&gt; &lt;span class='vi'&gt;@meeting&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt; &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;form&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt; &lt;span class='cp'&gt;%&amp;gt;&lt;/span&gt;&lt;span class='x' /&gt;
&lt;span class='x'&gt;      &lt;/span&gt;&lt;span class='cp'&gt;&amp;lt;%&lt;/span&gt; &lt;span class='n'&gt;form&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;inputs&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt; &lt;span class='cp'&gt;%&amp;gt;&lt;/span&gt;&lt;span class='x' /&gt;
&lt;span class='x'&gt;        &lt;/span&gt;&lt;span class='cp'&gt;&amp;lt;%=&lt;/span&gt; &lt;span class='n'&gt;form&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;input&lt;/span&gt; &lt;span class='ss'&gt;:title&lt;/span&gt; &lt;span class='cp'&gt;%&amp;gt;&lt;/span&gt;&lt;span class='x' /&gt;
&lt;span class='x'&gt;        &lt;/span&gt;&lt;span class='cp'&gt;&amp;lt;%=&lt;/span&gt; &lt;span class='n'&gt;form&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;input&lt;/span&gt; &lt;span class='ss'&gt;:week&lt;/span&gt; &lt;span class='cp'&gt;%&amp;gt;&lt;/span&gt;&lt;span class='x' /&gt;
&lt;span class='x'&gt;      &lt;/span&gt;&lt;span class='cp'&gt;&amp;lt;%&lt;/span&gt; &lt;span class='k'&gt;end&lt;/span&gt; &lt;span class='cp'&gt;%&amp;gt;&lt;/span&gt;&lt;span class='x' /&gt;
&lt;span class='x'&gt;      &lt;/span&gt;&lt;span class='cp'&gt;&amp;lt;%&lt;/span&gt; &lt;span class='n'&gt;form&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;buttons&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt; &lt;span class='cp'&gt;%&amp;gt;&lt;/span&gt;&lt;span class='x' /&gt;
&lt;span class='x'&gt;        &lt;/span&gt;&lt;span class='cp'&gt;&amp;lt;%=&lt;/span&gt; &lt;span class='n'&gt;form&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;commit_button&lt;/span&gt; &lt;span class='cp'&gt;%&amp;gt;&lt;/span&gt;&lt;span class='x' /&gt;
&lt;span class='x'&gt;      &lt;/span&gt;&lt;span class='cp'&gt;&amp;lt;%&lt;/span&gt; &lt;span class='k'&gt;end&lt;/span&gt; &lt;span class='cp'&gt;%&amp;gt;&lt;/span&gt;&lt;span class='x' /&gt;
&lt;span class='x'&gt;    &lt;/span&gt;&lt;span class='cp'&gt;&amp;lt;%&lt;/span&gt; &lt;span class='k'&gt;end&lt;/span&gt; &lt;span class='cp'&gt;%&amp;gt;&lt;/span&gt;&lt;span class='x' /&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;/p&gt;

&lt;p&gt;Formtastic is smart enough to detect your attribute types and renders an appropriate form element. If you don&amp;#8217;t like what it chooses, overriding the element type is as easy as an extra option to the input method.&lt;/p&gt;

&lt;p&gt;One limitation is that it only supports the standard form elements available in the rails API. What if you want something different - like some fancy image based thing? or a non-standard date picker? or some new-fandangled HTML5 input type?&lt;/p&gt;

&lt;p&gt;The readme has a tantalising hint on custom inputs, but doesn&amp;#8217;t go into much detail&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='text'&gt;    If you want to add your own input types to encapsulate your own logic or
    interface patterns, you can do so by subclassing SemanticFormBuilder and
    configuring Formtastic to use your custom builder class.
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Imagine your model has a date attribute that always stores a Monday. You want users to pick a date by selecting from a list of options formatted with commercial weeks (week 22 2010, week 23 2010, etc).&lt;/p&gt;

&lt;p&gt;Start by creating lib/my_custom_builder.rb. Create a class that extends the default formtastic builder and add your own input type. The default builder has a heap of helper methods you can use, so have that open at the same time.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;    &lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;MyCustomBuilder&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='no'&gt;Formtastic&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;SemanticFormBuilder&lt;/span&gt;
      &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;commercial_week_input&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;method&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;options&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='p'&gt;{})&lt;/span&gt;
        &lt;span class='n'&gt;options&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;set_include_blank&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;options&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
        &lt;span class='n'&gt;html_options&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;options&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;delete&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:input_html&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;||&lt;/span&gt; &lt;span class='p'&gt;{}&lt;/span&gt;
        &lt;span class='n'&gt;input_name&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;generate_association_input_name&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;method&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
        &lt;span class='n'&gt;selected_value&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='vi'&gt;@object&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;send&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;input_name&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
        &lt;span class='n'&gt;selected_value&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;selected_value&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;strftime&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;%Y-%m-%d&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='n'&gt;selected_value&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;respond_to?&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:strftime&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
        &lt;span class='n'&gt;select_options&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;strip_formtastic_options&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;options&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;merge&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:selected&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;selected_value&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;

        &lt;span class='n'&gt;collection&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;mondays&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;map&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;mon&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt; &lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='n'&gt;mon&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;strftime&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;Week %W, %Y&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt; &lt;span class='n'&gt;mon&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;strftime&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;%Y-%m-%d&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='p'&gt;}&lt;/span&gt;

        &lt;span class='nb'&gt;self&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;label&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;method&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;options_for_label&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;options&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&amp;lt;&lt;/span&gt;
          &lt;span class='nb'&gt;self&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;select&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;input_name&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;collection&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;select_options&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;html_options&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
      &lt;span class='k'&gt;end&lt;/span&gt;

      &lt;span class='kp'&gt;private&lt;/span&gt;

      &lt;span class='c1'&gt;# return an array of dates for the next year of mondays&lt;/span&gt;
      &lt;span class='c1'&gt;#&lt;/span&gt;
      &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;mondays&lt;/span&gt;
        &lt;span class='n'&gt;this_monday&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;Date&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;today&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;beginning_of_week&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;to_date&lt;/span&gt;
        &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;.&lt;/span&gt;&lt;span class='mi'&gt;51&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;map&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;i&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt; &lt;span class='n'&gt;this_monday&lt;/span&gt; &lt;span class='o'&gt;+&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;i&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='mi'&gt;7&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
      &lt;span class='k'&gt;end&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Then edit your formtastic settings in config/initializers/formtastic.rb and tell it to use your new builder instead of the default&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;    &lt;span class='no'&gt;Formtastic&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;SemanticFormHelper&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;builder&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;MyCustomBuilder&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Restart your app, and then use the new input type in a form&lt;/p&gt;

&lt;p&gt;&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='erb'&gt;&lt;span class='x'&gt;    &lt;/span&gt;&lt;span class='cp'&gt;&amp;lt;%&lt;/span&gt; &lt;span class='n'&gt;semantic_form_for&lt;/span&gt; &lt;span class='vi'&gt;@meeting&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt; &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;form&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt; &lt;span class='cp'&gt;%&amp;gt;&lt;/span&gt;&lt;span class='x' /&gt;
&lt;span class='x'&gt;      &lt;/span&gt;&lt;span class='cp'&gt;&amp;lt;%&lt;/span&gt; &lt;span class='n'&gt;form&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;inputs&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt; &lt;span class='cp'&gt;%&amp;gt;&lt;/span&gt;&lt;span class='x' /&gt;
&lt;span class='x'&gt;        &lt;/span&gt;&lt;span class='cp'&gt;&amp;lt;%=&lt;/span&gt; &lt;span class='n'&gt;form&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;input&lt;/span&gt; &lt;span class='ss'&gt;:title&lt;/span&gt; &lt;span class='cp'&gt;%&amp;gt;&lt;/span&gt;&lt;span class='x' /&gt;
&lt;span class='x'&gt;        &lt;/span&gt;&lt;span class='cp'&gt;&amp;lt;%=&lt;/span&gt; &lt;span class='n'&gt;form&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;input&lt;/span&gt; &lt;span class='ss'&gt;:week&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:as&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ss'&gt;:commercial_week&lt;/span&gt; &lt;span class='cp'&gt;%&amp;gt;&lt;/span&gt;&lt;span class='x' /&gt;
&lt;span class='x'&gt;      &lt;/span&gt;&lt;span class='cp'&gt;&amp;lt;%&lt;/span&gt; &lt;span class='k'&gt;end&lt;/span&gt; &lt;span class='cp'&gt;%&amp;gt;&lt;/span&gt;&lt;span class='x' /&gt;
&lt;span class='x'&gt;      &lt;/span&gt;&lt;span class='cp'&gt;&amp;lt;%&lt;/span&gt; &lt;span class='n'&gt;form&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;buttons&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt; &lt;span class='cp'&gt;%&amp;gt;&lt;/span&gt;&lt;span class='x' /&gt;
&lt;span class='x'&gt;        &lt;/span&gt;&lt;span class='cp'&gt;&amp;lt;%=&lt;/span&gt; &lt;span class='n'&gt;form&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;commit_button&lt;/span&gt; &lt;span class='cp'&gt;%&amp;gt;&lt;/span&gt;&lt;span class='x' /&gt;
&lt;span class='x'&gt;      &lt;/span&gt;&lt;span class='cp'&gt;&amp;lt;%&lt;/span&gt; &lt;span class='k'&gt;end&lt;/span&gt; &lt;span class='cp'&gt;%&amp;gt;&lt;/span&gt;&lt;span class='x' /&gt;
&lt;span class='x'&gt;    &lt;/span&gt;&lt;span class='cp'&gt;&amp;lt;%&lt;/span&gt; &lt;span class='k'&gt;end&lt;/span&gt; &lt;span class='cp'&gt;%&amp;gt;&lt;/span&gt;&lt;span class='x' /&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;/p&gt;</description>
    </item>
  
    <item>
      <title>Flash 10 On 64bit Debian</title>
      <link>http://yob.id.au/2010/05/22/flash-10-on-64bit-debian.html</link>
      <guid>http://yob.id.au/2010/05/22/flash-10-on-64bit-debian</guid>
      <pubDate>Sat, 22 May 2010 00:00:00 +1000</pubDate>
      <description>&lt;p&gt;Debian recently removed flash from their AMD64 to security issues and Adobe dropping official support.&lt;/p&gt;

&lt;p&gt;I dislike flash as much as the next self respecting web developer, but some site (like google analytics) are pretty useless without it.&lt;/p&gt;

&lt;p&gt;If you need a temporary solution to getting it up and running, manually download and install the old flash9 package from backports&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;    wget http://backports.mithril-linux.org/pool/contrib/f/flashplugin-nonfree/flashplugin-nonfree_1.4~bpo40+1_amd64.deb
    sudo dpkg -i flashplugin-nonfree_1.4~bpo40+1_amd64.deb
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;For further reading, check out the backports page for &lt;a href='http://packages.debian.org/etch-backports/flashplugin-nonfree'&gt;flashplugin-nonfree&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s ye olde, but it works.&lt;/p&gt;</description>
    </item>
  
    <item>
      <title>New Mysql Ruby Bindings</title>
      <link>http://yob.id.au/2010/05/20/new-mysql-ruby-bindings.html</link>
      <guid>http://yob.id.au/2010/05/20/new-mysql-ruby-bindings</guid>
      <pubDate>Thu, 20 May 2010 00:00:00 +1000</pubDate>
      <description>&lt;p&gt;There&amp;#8217;s been some recent discussions about the way ruby 1.9 handles encodings and the exceptions people are running into, particularly when running rails.&lt;/p&gt;

&lt;p&gt;A lot of the time, the exceptions are caused by database drivers passing back multi-byte strings incorrectly tagged as ASCII-8BIT instead of UTF-8.&lt;/p&gt;

&lt;p&gt;The work around was ususally to do something like the monkey patch described &lt;a href='http://gnuu.org/2009/11/06/ruby19-rails-mysql-utf8/'&gt;here&lt;/a&gt;. I&amp;#8217;ve used that particular patch in production for a few months and it works fine, but monkey patches make me squirm.&lt;/p&gt;

&lt;p&gt;This week I was finally able to replace the patch with an alternative mysql gem that retrieves all strings from the database as utf-8 and marks them correctly.&lt;/p&gt;

&lt;p&gt;Brian Mario has released &lt;a href='http://github.com/brianmario/mysql2'&gt;mysql2&lt;/a&gt;. The basic API is different to the standard mysql gem, but he&amp;#8217;s included an ActiveRecord adapter that acts as a drop-in replacement for the mysql one.&lt;/p&gt;

&lt;p&gt;To give mysql2 a go in rails install the gem:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;    gem install mysql2
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Then update your database.yml:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='yaml'&gt;    &lt;span class='l-Scalar-Plain'&gt;development&lt;/span&gt;&lt;span class='p-Indicator'&gt;:&lt;/span&gt;
      &lt;span class='l-Scalar-Plain'&gt;adapter&lt;/span&gt;&lt;span class='p-Indicator'&gt;:&lt;/span&gt; &lt;span class='l-Scalar-Plain'&gt;mysql2&lt;/span&gt;
      &lt;span class='l-Scalar-Plain'&gt;database&lt;/span&gt;&lt;span class='p-Indicator'&gt;:&lt;/span&gt; &lt;span class='l-Scalar-Plain'&gt;myapp_dev&lt;/span&gt;
      &lt;span class='l-Scalar-Plain'&gt;username&lt;/span&gt;&lt;span class='p-Indicator'&gt;:&lt;/span&gt; &lt;span class='l-Scalar-Plain'&gt;foo&lt;/span&gt;
      &lt;span class='l-Scalar-Plain'&gt;password&lt;/span&gt;&lt;span class='p-Indicator'&gt;:&lt;/span&gt; &lt;span class='l-Scalar-Plain'&gt;bar&lt;/span&gt;
      &lt;span class='l-Scalar-Plain'&gt;host&lt;/span&gt;&lt;span class='p-Indicator'&gt;:&lt;/span&gt; &lt;span class='l-Scalar-Plain'&gt;localhost&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Make sure you get mysql2 version 0.1.6 or higher, in lower versions the ActiveRecord adaptor behaved slightly differently from the default Mysql one.&lt;/p&gt;

&lt;p&gt;Brian is incredibly responsive to bug reports, so if you have any issues make sure you report them on the github project.&lt;/p&gt;</description>
    </item>
  
    <item>
      <title>Ethical Superannuation</title>
      <link>http://yob.id.au/2010/01/16/ethical-superannuation.html</link>
      <guid>http://yob.id.au/2010/01/16/ethical-superannuation</guid>
      <pubDate>Sat, 16 Jan 2010 00:00:00 +1100</pubDate>
      <description>&lt;p&gt;For all of my (admittedly short) professional life, my superannuation has been in &lt;a href='http://australiansuper.com/'&gt;Australian Super&amp;#8217;s&lt;/a&gt; Sustainable Balanced fund.&lt;/p&gt;

&lt;p&gt;I was more or less happy with this. Conventional wisdom says that non-profit industry super funds tend to perform better than commercial funds due to lower fees, and the sustainable option meant my money wasn&amp;#8217;t being invested in too many companies I disagreed with.&lt;/p&gt;

&lt;p&gt;However, I recently received a letter from Australian Super informing me of an upcoming change in their sustainable investment policies. The key paragraph was:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;In the past our investment manager excluded companies that it believed to
receive a significant proportion of their revenue (at least 5%) from the
manufacture of sale of alcohol or tobacco, the operation of gaming
facilities or the manufacture of gambling equipment, uranium extraction or
the manufacture of weapons or armaments. This automatic exclusion will no
longer take place.&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Hah. Imagine that. Presumably they were sick of missing investment returns from companies like BHP that are involved in uranium.&lt;/p&gt;

&lt;p&gt;Whatever their reasoning, chances are my money is now being invested in places I&amp;#8217;d prefer it not to be, so I&amp;#8217;ve been researching my options.&lt;/p&gt;

&lt;p&gt;The obvious alternative is &lt;a href='http://www.australianethical.com.au'&gt;Australian Ethical Super&lt;/a&gt;. Their investment policies gel strongly with my preferences and my non-super investments with them have been performing well.&lt;/p&gt;

&lt;p&gt;Being a commercial fund, a comparison of fees was in order. The results were surprising and a little disappointing.&lt;/p&gt;

&lt;p&gt;&lt;a href='http://australiansuper.com/formembers_feesandothercharges.aspx'&gt;Australian Super&amp;#8217;s Fees&lt;/a&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$78/year administration costs
0.77% of account balance
0% of contributions&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a href='http://www.australianethical.com.au/fees-and-costs-individuals'&gt;Australian Ethical Fees&lt;/a&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$41/year administration costs
2.15% of account balance, calculated weekly
4.1% of contributions&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For the 08-09 financial year, Australian Ethical fees for my super balance would&amp;#8217;ve been a little more than &lt;em&gt;triple&lt;/em&gt; what I actually paid Australian Super. Bugger.&lt;/p&gt;

&lt;p&gt;All this is ignoring historical returns for each fund, a topic that would demand an entirely separate blog post. The short of it is that over the previous 5 years, Australian Ethical seems to have performed worse on comparable funds.&lt;/p&gt;

&lt;p&gt;So do I move? Are there other ethical super options out there? What premium am I willing to cop in return for having my money invested in ethical companies?&lt;/p&gt;</description>
    </item>
  
    <item>
      <title>Intro To The Pdf File Structure</title>
      <link>http://yob.id.au/2009/11/12/intro-to-the-pdf-file-structure.html</link>
      <guid>http://yob.id.au/2009/11/12/intro-to-the-pdf-file-structure</guid>
      <pubDate>Thu, 12 Nov 2009 00:00:00 +1100</pubDate>
      <description>&lt;p&gt;For a couple of years I&amp;#8217;ve been involved in various PDF related Ruby projects - most recently in &lt;a href='http://prawn.majesticseacreature.com/'&gt;prawn&lt;/a&gt;, a pure ruby PDF generation library.&lt;/p&gt;

&lt;p&gt;Prawn is a long way from implementing all parts of the spec and there has been no shortage of people who desire support for various features. Many of these users are the kind who will submit a patch to an open source project when they find a missing feature, yet this has only happened to prawn in a small number of cases.&lt;/p&gt;

&lt;p&gt;The PDF spec is epic (version 1.7 is over 1300 pages), yet the basic structure is less complicated than it first appears. Don&amp;#8217;t be put off! We&amp;#8217;d love more contributors to prawn, so this post is intended to be a basic introduction to reading a PDF file - the first step in understanding how prawn does the reverse process. I&amp;#8217;ve created a &lt;a href='/files/hexagon.pdf'&gt;simple PDF&lt;/a&gt; to use as an example.&lt;/p&gt;

&lt;p&gt;The best way to think of the file is a set of objects (strings, hashes, symbols, integers, arrays, etc) in an object tree that descends from a single &amp;#8220;root&amp;#8221; hash.&lt;/p&gt;

&lt;p&gt;To start navigating the &lt;a href='/files/hexagon.pdf'&gt;example file&lt;/a&gt; by eye, open it in a text editor and browse to the last line. Just above the end of the file token (%%EOF) is a number that indicates a byte offset in the file.&lt;/p&gt;

&lt;p&gt;That byte offset points to the &amp;#8220;xref&amp;#8221; token on line 46. Everything between here and the &amp;#8220;trailer&amp;#8221; token several lines below is called the Cross Reference Table (xref table to its friends). &amp;#8220;0 6&amp;#8221; indicates that this file has 5 objects in it numbered 1-5 (plus a number 0 null object). The following lines indicate object 1 is at byte offset 15, object 2 at offset 71, etc.&lt;/p&gt;

&lt;p&gt;After the byte offsets you&amp;#8217;ll see the following lines:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;    &lt;span class='o'&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class='sr'&gt;/Info 1 0 R&lt;/span&gt;
&lt;span class='sr'&gt;    /&lt;/span&gt;&lt;span class='no'&gt;Size&lt;/span&gt; &lt;span class='mi'&gt;6&lt;/span&gt;
    &lt;span class='o'&gt;/&lt;/span&gt;&lt;span class='no'&gt;Root&lt;/span&gt; &lt;span class='mi'&gt;3&lt;/span&gt; &lt;span class='mi'&gt;0&lt;/span&gt; &lt;span class='n'&gt;R&lt;/span&gt;
    &lt;span class='o'&gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This is called the trailer and it is a serialised hashmap. In Ruby syntax, this would look something like:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;    &lt;span class='p'&gt;{&lt;/span&gt;
      &lt;span class='ss'&gt;:Info&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;1 0 R&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
      &lt;span class='ss'&gt;:Size&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='mi'&gt;6&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
      &lt;span class='ss'&gt;:Root&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;3 0 R&amp;quot;&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This is the top of our object tree. &amp;#8220;1 0 R&amp;#8221; is the syntax for pointing to object #1. Using our xref table we can see object 1 is at byte 17 and it looks like this:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;    &lt;span class='o'&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class='sr'&gt;/Creator (Prawn)&lt;/span&gt;
&lt;span class='sr'&gt;    /&lt;/span&gt;&lt;span class='no'&gt;Producer&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='no'&gt;Prawn&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='o'&gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;It&amp;#8217;s another hash that looks like this in Ruby:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;    &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='ss'&gt;:Creator&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;Prawn&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:Producer&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;Prawn&amp;quot;&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Merge this with our trailer hash and our object tree now looks like:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;    &lt;span class='p'&gt;{&lt;/span&gt;
      &lt;span class='ss'&gt;:Info&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='ss'&gt;:Creator&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;Prawn&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:Producer&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;Prawn&amp;quot;&lt;/span&gt; &lt;span class='p'&gt;},&lt;/span&gt;
      &lt;span class='ss'&gt;:Size&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='mi'&gt;6&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
      &lt;span class='ss'&gt;:Root&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;3 0 R&amp;quot;&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Repeat this process for every time you see &amp;#8220;n 0 R&amp;#8221; (called an indirect object) and you will have a complete PDF object graph.&lt;/p&gt;

&lt;p&gt;Prawn&amp;#8217;s job is to do the reverse - build an object graph that conforms to the spec and serialise it to a file in the correct format. Prawn has all the tools for serialising standard ruby objects into their PDF representation, so the trick is to find the correct place to add your new information (an extra font, an advanced colour definition, whatever) and insert it as a ruby object. Usually this means something like adding an entry to an array or hash.&lt;/p&gt;

&lt;p&gt;Once that&amp;#8217;s done, prawn will handle the serialisation when a user calls render.&lt;/p&gt;

&lt;p&gt;For homework, download a copy of the &lt;a href='http://www.adobe.com/devnet/acrobat/pdfs/PDF32000_2008.pdf'&gt;PDF spec&lt;/a&gt; and read chapter 7 (particularly sections 7.3, 7.5, 7.7, 7.8 and 7.9). Also check out &lt;a href='http://github.com/sandal/prawn/blob/4b7f1a4d975b3478dad184bd56c7f53e7d92b784/lib/prawn/pdf_object.rb'&gt;lib/prawn/pdf_object.rb&lt;/a&gt; to see how prawn converts each Ruby object into PDF equivalents.&lt;/p&gt;</description>
    </item>
  
  </channel>
</rss>

