<?xml version="1.0" encoding="UTF-8"?>
<entries type="array">
  <entry>
    <author>Robin Fisher</author>
    <body>This inaugural post comes after several days of arguing with Ubuntu, Apache and Mongrel.

This site is hosted on a 256 slice from &lt;a href="http://www.slicehost.com/"&gt;Slicehost&lt;/a&gt; and I've learnt a lot about Apache configuration, working with Linux and am now intimately familiar with the command line.

During the process, I've been helped by a significant number of resources that are out there and I intend to run a series of posts on how I got this site up and running in the hope that I may &lt;a href="http://blog.codahale.com/2006/06/19/time-for-a-grown-up-server-rails-mongrel-apache-capistrano-and-you/"&gt;stand on the shoulders of giants&lt;/a&gt; and provide some insight of my own.

As a side note, you might have seen that this site is running on "sparky".  This is a custom built CMS coded in Rails that is very much in version 0.1.  I'll be doing some posts on its development as well as walking through some features as I add them.</body>
    <created-at type="datetime">2008-02-07T22:38:27+00:00</created-at>
    <id type="integer">1</id>
    <month-year>February 2008</month-year>
    <published type="boolean">true</published>
    <summary nil="true"></summary>
    <title>Welcome to captured sparks</title>
    <updated-at type="datetime">2008-05-18T16:16:40+00:00</updated-at>
  </entry>
  <entry>
    <author>Robin Fisher</author>
    <body>Would I have swapped the struggles of the last few days in terms of getting this up and running for the simplicity of &lt;a href="http://heroku.com/"&gt;Heroku&lt;/a&gt;?

I'm not sure that I would.</body>
    <created-at type="datetime">2008-02-08T08:36:42+00:00</created-at>
    <id type="integer">2</id>
    <month-year>February 2008</month-year>
    <published type="boolean">true</published>
    <summary nil="true"></summary>
    <title>Heroku</title>
    <updated-at type="datetime">2008-05-18T16:16:40+00:00</updated-at>
  </entry>
  <entry>
    <author>Robin Fisher</author>
    <body>It occurred to me late last night that due to my use of Capistrano to deploy sparky, any images that were uploaded were getting lost every time I deployed.

Thanks to &lt;a href="http://www.almosteffortless.com/2007/03/25/working-with-attachment_fu/"&gt;a great article at almost effortless&lt;/a&gt;, I thought I had the problem solved.

Unfortunately, attachment_fu seems insistent on adding leading slashes, leading directories and all manner of things to the public_filename path.  As such, all my images have disappeared until such time as I can fix this.</body>
    <created-at type="datetime">2008-02-08T22:12:23+00:00</created-at>
    <id type="integer">3</id>
    <month-year>February 2008</month-year>
    <published type="boolean">true</published>
    <summary nil="true"></summary>
    <title>attachment_fu - where are the images?</title>
    <updated-at type="datetime">2008-05-18T16:16:40+00:00</updated-at>
  </entry>
  <entry>
    <author>Robin Fisher</author>
    <body>Just as I shut the laptop last night to go to bed, I came up with a solution to my leading slash problem.

attachment_fu's default behaviour is to partition the directories into which it stores files based on id.  In my case, my images were being placed into the folder public/images/0000/#{id}.

As such, I amended my deploy.rb file to read:

&lt;code:ruby&gt;
task :after_update_code, :roles =&gt; :app do
  %w{0000}.each do |share|
    run "rm -rf #{release_path}/public/images/#{share}"
    run "mkdir -p #{shared_path}/system/images/#{share}"
    run "ln -s #{shared_path}/system/images/#{share} #{release_path}/public/images/#{share}"
  end
end
&lt;/code&gt;

This symlinked the 0000 directory to an identically named directory in the shared part of the system.

I've deployed a couple of times since then and my images are still accessible.</body>
    <created-at type="datetime">2008-02-09T08:18:48+00:00</created-at>
    <id type="integer">4</id>
    <month-year>February 2008</month-year>
    <published type="boolean">true</published>
    <summary nil="true"></summary>
    <title>attachment_fu problem fixed</title>
    <updated-at type="datetime">2008-05-18T16:16:40+00:00</updated-at>
  </entry>
  <entry>
    <author>Robin Fisher</author>
    <body>As part of the home page on captured sparks, I wanted to have a "Recent Reads" section where I could list the articles that have caught my attention recently.  I do most of my reading in Google Reader and thought that the Shared Items feature in Reader would be perfect for this.  Thanks to the FeedTools gem, adding this was straightforward.

Firstly, grab the FeedTools gem, using sudo if necessary:

&lt;pre&gt;gem install feedtools&lt;/pre&gt;

The way I added this function was to use a helper method inside my home_helper.rb call shared_items.  Firstly require the gem in the head of the helper:

&lt;code:ruby&gt;
gem 'feedtools'
require 'feed_tools'
&lt;/code&gt;

Next, set up some variables that we will use throughout the method:

&lt;dl&gt;
&lt;dt&gt;&lt;pre&gt;content&lt;/pre&gt;&lt;/dt&gt;
&lt;dd&gt;will be used to contain our shared items&lt;/dd&gt;
&lt;dt&gt;&lt;pre&gt;days&lt;/pre&gt;&lt;/dt&gt;
&lt;dd&gt;used to calculate how old the oldest shared item will be&lt;/dd&gt;
&lt;dt&gt;&lt;pre&gt;time&lt;/pre&gt;&lt;/dt&gt;
&lt;dd&gt;used to make sure each entry is not too old&lt;/dd&gt;
&lt;dt&gt;&lt;pre&gt;share_url&lt;/pre&gt;&lt;/dt&gt;
&lt;dd&gt;the RSS feed for the shared items&lt;/dd&gt;
&lt;/dl&gt;

Setting up the method now looks like:

&lt;code:ruby&gt;
content = ''
days = 15
time = Time.now.utc - (86400 * days.to_i)
share_url = 'http://www.google.com/reader/public/atom/user/13411963057092720812/state/com.google/broadcast'
&lt;/code&gt;

To create the shared item list:

&lt;code:ruby&gt;
feed = FeedTools::Feed.open(share_url)
  feed.entries.each do |entry|
    if entry.published &gt; time
      content &lt;&lt; " &lt;li&gt;\n"
      content &lt;&lt; " &lt;a href='#{entry.link}'&gt;#{entry.title}&lt;/a&gt;\n"
      content &lt;&lt; " &lt;p /&gt;#{entry.find_node("source/title/text()").to_s}\n"
      content &lt;&lt; " &lt;/li&gt;\n"
    end
  end
&lt;/code&gt;

Finally, check to see if anything is shared and add the appropriate HTML container (or witty comment if nothing is shared), then return the content.

&lt;code:ruby&gt;
if content.length &gt; 0
  content = "&lt;ul&gt;" + content
  content &lt;&lt; "&lt;/ul&gt;\n"
else
  content = "&lt;p /&gt;Not read anything of interest recently."
end
return content
&lt;/code&gt;

The helper method is then called in the view by simply adding:

&lt;code:ruby&gt;&lt;%= shared_items %&gt;&lt;/code&gt;

You can read more about FeedTools in the &lt;a href="http://feedtools.rubyforge.org/"&gt;FeedTools API&lt;/a&gt;.

</body>
    <created-at type="datetime">2008-02-10T14:33:07+00:00</created-at>
    <id type="integer">5</id>
    <month-year>February 2008</month-year>
    <published type="boolean">true</published>
    <summary nil="true"></summary>
    <title>Integrating Google Shared Items with Rails</title>
    <updated-at type="datetime">2008-05-18T16:16:40+00:00</updated-at>
  </entry>
  <entry>
    <author>Robin Fisher</author>
    <body>Having worked in a multi-national corporate for the last 6 years, it is common practice for me to refer to a company as "we". You may have noticed that I use "we" when talking about captured sparks on this site. The headline on the homepage is "We can make your website sparkle".

We, in the case of captured sparks, is me. It is I. One person.

Should it ever get to the stage where other people come on board, I'll let you know. Until then, it's just me.  Even when I say "we".</body>
    <created-at type="datetime">2008-02-10T19:31:41+00:00</created-at>
    <id type="integer">6</id>
    <month-year>February 2008</month-year>
    <published type="boolean">true</published>
    <summary nil="true"></summary>
    <title>Of We and I</title>
    <updated-at type="datetime">2008-05-18T16:16:40+00:00</updated-at>
  </entry>
  <entry>
    <author>Robin Fisher</author>
    <body>One of the things that had me confused early on when programming in Ruby was when to use "self" for a method and when not to.

The easiest way to summarise, I think, is to say that &lt;pre&gt;self.method&lt;/pre&gt; should be used when referring to a method that operates on the class itself.  &lt;pre&gt;method&lt;/pre&gt; should be used when referring to a method that operates on an instance of the class.

The most common place this is seen in Rails application is in authentication systems.  The method for logging a user into an application is usually written as:

&lt;code:ruby&gt;
Class User &lt; ActiveRecord::Base

  def self.authenticate(user, password)
    ...
  end

end
&lt;/code&gt;

This is then called in the controller as:

&lt;code:ruby&gt;
Class SessionsController &lt; ActionController::Base

  def new
    @user = User.authenticate(params[:session])
  end

end
&lt;/code&gt;

In contrast, methods can then be called on the @user object once the user has logged in.  For example, to check if the user is an administrator, the following method could be used in our User class:

&lt;code:ruby&gt;
def is_admin?
  ...
end
&lt;/code&gt;

This could then be called within the view, perhaps to display certain restricted information:

&lt;code:ruby&gt;
&lt;%= if @user.is_admin? %&gt;
&lt;/code&gt;

As a complete aside, I love how the above code demonstrates the readability of Ruby.  There is no doubt as to what that statement means.</body>
    <created-at type="datetime">2008-02-12T10:45:11+00:00</created-at>
    <id type="integer">7</id>
    <month-year>February 2008</month-year>
    <published type="boolean">true</published>
    <summary nil="true"></summary>
    <title>Using self in Ruby</title>
    <updated-at type="datetime">2008-05-18T16:16:40+00:00</updated-at>
  </entry>
  <entry>
    <author>Robin Fisher</author>
    <body>A &lt;a href="http://technology.timesonline.co.uk/tol/news/tech_and_web/the_web/article3353387.ece"&gt;report in the Times&lt;/a&gt; this morning is getting a lot of coverage.  It states that the UK government intends to legislate to require ISPs to take action against individuals using their networks for file-sharing activities.

Quite how the government expects ISPs to monitor every bit of traffic that passes through their network is anyone's guess.  It is again indicative of the music industry's insistence on spending their money on lobbying for legislation to protect a failing business model, rather than adapting to the changing face of music.

Becky Hogge of the &lt;a href="http://www.openrightsgroup.org"&gt;Open Rights Group&lt;/a&gt; (an organisation for which I volunteer) is appearing opposite the BPI on Radio 4's World at One to discuss the story.  ORG will no doubt be responding to any future consultation.

For further reading on the story, I recommend &lt;a href="http://uk.techcrunch.com/2008/02/12/the-sheer-craven-stupidity-of-government-regulation-of-online-music"&gt;Techcrunch UK&lt;/a&gt;, &lt;a href="http://www.techcrunch.com/2008/02/12/uk-proposes-three-strikes-and-your-out-illegal-downloading-law/"&gt;Techcrunch&lt;/a&gt;, the &lt;a href="http://www.techdirt.com/articles/20080211/220305233.shtml"&gt;always excellent Techdirt&lt;/a&gt; and &lt;a href="http://www.bbc.co.uk/blogs/technology/2008/02/uk_takes_tough_stance_on_pirac.html"&gt;BBC News' Darren Waters&lt;/a&gt;.

UPDATE: ORG have &lt;a href="http://www.openrightsgroup.org/2008/02/12/government-to-ban-illegal-filesharers-from-the-internet/"&gt;a post about this story&lt;/a&gt;.</body>
    <created-at type="datetime">2008-02-12T11:38:05+00:00</created-at>
    <id type="integer">8</id>
    <month-year>February 2008</month-year>
    <published type="boolean">true</published>
    <summary nil="true"></summary>
    <title>UK to ban filesharers from the net?</title>
    <updated-at type="datetime">2008-05-18T16:16:40+00:00</updated-at>
  </entry>
  <entry>
    <author>Robin Fisher</author>
    <body>Inspired by &lt;a href="http://www.snook.ca/archives/other/effective_blog_comment_spam_blocker"&gt;Jonathan&lt;/a&gt;, I spent some time last night working on spam prevention for the comments here at captured sparks.  I had seen a good article on integrating Akismet with Rails but as this is a home-baked CMS, and having read &lt;a href="http://www.snook.ca/archives/other/effective_blog_comment_spam_blocker"&gt;Jonathan's approach to the issue&lt;/a&gt; decided to have a go myself.

I adopted a similar approach to Jonathan of assigning a score to a comment and then either automatically posting the comment or holding it back for approval .  The validation is handled by a before_create callback in the comment model.  Here's an extract of the validation method:

&lt;code:ruby&gt;
body = self.body
...
score -= body.scan(/viagra/).size
...
case score
when 1..999
 write_attribute(:approved, true)
...
&lt;/code&gt;

At the moment, the validation is very basic and leans towards a cautious approach to automatic posting.  Having said that, all comments are saved to the database for review.  I'm not content enough to start automatically rejecting the comments yet.

Thank to Jonathan for the inspiration.</body>
    <created-at type="datetime">2008-02-13T12:52:46+00:00</created-at>
    <id type="integer">9</id>
    <month-year>February 2008</month-year>
    <published type="boolean">true</published>
    <summary nil="true"></summary>
    <title>Custom spam prevention</title>
    <updated-at type="datetime">2008-05-18T16:16:40+00:00</updated-at>
  </entry>
  <entry>
    <author>Robin Fisher</author>
    <body>One to watch over at &lt;a href="http://nextupdate.com/"&gt;Next Update&lt;/a&gt;, where they are blogging the building of their issue and bug tracking app.</body>
    <created-at type="datetime">2008-02-15T08:51:17+00:00</created-at>
    <id type="integer">10</id>
    <month-year>February 2008</month-year>
    <published type="boolean">true</published>
    <summary nil="true"></summary>
    <title>Blogging the building of your app</title>
    <updated-at type="datetime">2008-05-18T16:16:40+00:00</updated-at>
  </entry>
  <entry>
    <author>Robin Fisher</author>
    <body>I've come up with a little idea for a web app.

It's going to be for a niche market where the current solutions to the issue are enterprise level with a huge server licence and slightly-less-huge user licences. There is a lot of competition for the traditional solution but none for a simple, hosted solution.

The market I am targeting is historically very traditional and this may present a small barrier to adoption but this is for the sector in which I currently work and &lt;em&gt;I&lt;/em&gt; know that &lt;em&gt;I&lt;/em&gt; would want something like this.

It's not going to come as a shock to say that I admire &lt;a href="http://www.37signals.com"&gt;37 Signals&lt;/a&gt; (who doesn't?). Part of their ethos though is to build what you know and what you use. That way, there is less chance of &lt;a href="http://en.wikipedia.org/wiki/Creeping_featurism"&gt;featuritis&lt;/a&gt;. And I know exactly what this app should do.</body>
    <created-at type="datetime">2008-02-16T08:55:12+00:00</created-at>
    <id type="integer">11</id>
    <month-year>February 2008</month-year>
    <published type="boolean">true</published>
    <summary nil="true"></summary>
    <title>Everyone should have a web app</title>
    <updated-at type="datetime">2008-05-18T16:16:41+00:00</updated-at>
  </entry>
  <entry>
    <author>Robin Fisher</author>
    <body>As I sit here, all sorts of ideas are popping into my head that would be awesome to implement for my upcoming app.  Unfortunately, they need to go on the back-burner.

I started work on the app yesterday afternoon and am still in the process of creating my models and controllers to give a basic functionality.  Whilst I do enjoy working in Rails, this is the boring bit.  I can't wait until I can really get into creating my own methods and putting some of these ideas into practice.</body>
    <created-at type="datetime">2008-02-18T12:26:33+00:00</created-at>
    <id type="integer">12</id>
    <month-year>February 2008</month-year>
    <published type="boolean">true</published>
    <summary nil="true"></summary>
    <title>The cool stuff has to wait</title>
    <updated-at type="datetime">2008-05-18T16:16:41+00:00</updated-at>
  </entry>
  <entry>
    <author>Robin Fisher</author>
    <body>As part of the development of my app, I had a need to display various different categories of to-do items - complete, overdue and "normal".

I was using a method in the Todo class similar to the following to create these categories:

&lt;code:ruby&gt;
def self.find_overdue
  overdue = Array.new
  items = find(:all)
  for item in items
    if item.overdue?
      overdue &lt;&lt; item
    else
    end
  end
  overdue
end
&lt;/code&gt;

I was reading through the online Ruby documentation on another issue and came across a nice method in the Hash class: reject.  This acts as a "delete if" method and can substantially reduce the code above:

&lt;code:ruby&gt;
def self.find_overdue
  items = find(:all)
  items.reject { |i| i.not_overdue? }
end
&lt;/code&gt;

The "not_overdue" method is defined separately in the Todo class.  I think this definitely shows the importance of knowing the Ruby language and equally demonstrates its power.</body>
    <created-at type="datetime">2008-02-22T10:53:10+00:00</created-at>
    <id type="integer">13</id>
    <month-year>February 2008</month-year>
    <published type="boolean">true</published>
    <summary nil="true"></summary>
    <title>The need to know Ruby</title>
    <updated-at type="datetime">2008-05-18T16:16:41+00:00</updated-at>
  </entry>
  <entry>
    <author>Robin Fisher</author>
    <body>One of the issues I encountered with my previous Rails application was adding a sitemap to the root directory so that I could use &lt;a href="http://www.google.com/webmasters/tools"&gt;Google's Webmaster Tools&lt;/a&gt;. As I was not under a deadline for sparky, I was able to dedicate some time to the issue.

I figured the easiest way to create the sitemap was to use Rails' built-in XML builder to dynamically generate the sitemap when requested by Google.  This has the advantage of picking up every new blog entry.

First was the controller.  In order to keep everything segregated and RESTful, I created a sitemaps controller with one action:

&lt;code:ruby&gt;
class SitemapController &lt; ApplicationController
  
  def sitemap
    @entries = Entry.find(:all)
    @jobs = Job.find(:all)
    
    respond_to do |format|
      format.xml { render :layout =&gt; false }
    end
  end
  
end
&lt;/code&gt;

I retrieve all the dynamic information in the controller, which is then passed to the view file.  Creating the view was a lot of trial and error, particularly in terms of getting it to match the sitemap specification.  Here though is the final view file split into chunks for commentary purposes.

&lt;code:ruby&gt;
base_url = "http://www.capturedsparks.com"
xml.instruct! :xml, :version=&gt;"1.0"
xml.tag! 'urlset', "xmlns" =&gt; "http://www.sitemaps.org/schemas/sitemap/0.9" do
&lt;/code&gt;

This sets the header information in the resulting xml file as required by the sitemap specification.

&lt;code:ruby&gt;
for entry in @entries do
  xml.tag! 'url' do
    xml.tag! 'loc', "#{base_url}#{generate_url(entry)}"
    xml.tag! 'lastmod', entry.updated_at.strftime("%Y-%m-%d")
    xml.tag! 'changefreq', 'monthly'
    xml.tag! 'priority', '0.8'
  end
end
&lt;/code&gt;

This iterates through the blog entries, which are contained in the @entries variable set in the controller.  This is then followed with identical code for the @jobs variable.

For each of the static pages (including the blog and job indexes), I use the following code assigning them higher priorities than the individual blog and job entries.

&lt;code:ruby&gt;
xml.tag! 'url' do
    xml.tag! 'loc', "http://www.capturedsparks.com/about/"
    xml.tag! 'changefreq', 'monthly'
    xml.tag! 'priority', '1'
end
&lt;/code&gt;

The resulting xml file can be seen &lt;a href="http://www.capturedsparks.com/sitemap.xml"&gt;here&lt;/a&gt;.</body>
    <created-at type="datetime">2008-02-25T21:59:30+00:00</created-at>
    <id type="integer">14</id>
    <month-year>February 2008</month-year>
    <published type="boolean">true</published>
    <summary nil="true"></summary>
    <title>Dynamically generating a sitemap for Google</title>
    <updated-at type="datetime">2008-05-18T16:16:41+00:00</updated-at>
  </entry>
  <entry>
    <author>Robin Fisher</author>
    <body>I've add a sidebar to the individual blog entry pages so that I can let visitors know that we do some web design.

Just to confirm that I haven't left off my ruby output tags.  The idea of using variable names was inspired by &lt;a href="http://wilwheaton.typepad.com/"&gt;Wil Wheaton&lt;/a&gt; and the auto-responder he used to have.</body>
    <created-at type="datetime">2008-02-25T22:35:11+00:00</created-at>
    <id type="integer">15</id>
    <month-year>February 2008</month-year>
    <published type="boolean">true</published>
    <summary nil="true"></summary>
    <title>About the sidebar</title>
    <updated-at type="datetime">2008-05-18T16:16:41+00:00</updated-at>
  </entry>
  <entry>
    <author>Robin Fisher</author>
    <body>Whilst creating my own blog software has made me realise how little I needed compared to the vast functionality of readily-available software, one of the things I did want was a monthly archive view.

The first thing I did was create a method in the Entry model that would assign each entry an "archive link" consisting of the month and year in which the entry was created:

&lt;code:ruby&gt;
class Entry &lt; ActiveRecord::Base

after_create :create_archive_link
...
def create_archive_link
  month = self.created_at.strftime("%B %Y")
  month = month.downcase.sub(/[ ]/, "")
  self.month_year = month
  self.save
end
&lt;/code&gt;

I have to confess at this point that I broke from the RESTful conventions that I try to employ and created a monthly_index method in the entries controller:

&lt;code:ruby&gt;
def monthly_index
  @entries = Entry.find_all_by_month_year(params[:month])
  @entry = @entries[1]
  @all_entries = Entry.find(:all)
end
&lt;/code&gt;

For the blog index, I then list the monthly archives using the following code:

&lt;code:rhtml&gt;
&lt;ul&gt;
  &lt;% @all_entries.group_by(&amp;:month_year).each do |month, entries| %&gt;
    &lt;li&gt;&lt;%= link_to "#{month} (#{entries.size})", monthly_archive_url(month.downcase.sub(/[ ]/, "")) %&gt;&lt;/li&gt;
  &lt;% end %&gt;
&lt;/ul&gt;
&lt;/code&gt;

This code does several things in a short space of time:

1) Groups each entry by a defined month_year method resulting in a hash keyed on the month_year method

2) Prepares to iterate through the hash based on the month_year key

3) Lists the month name and the number of posts in that month with a link to a monthly_archive_url route that is defined in routes.rb

In routes.rb, the following route is defined:

&lt;code:ruby&gt;
ActionController::Routing::Routes.draw do |map|
...
  map.monthly_archive 'entries/archive/:month', :controller =&gt; 'entries', :action =&gt; 'monthly_index'
...
end
&lt;/code&gt;

I think the code could be cleaned up a little bit by defining more methods in the model.  Just writing this has made me think that I should define a method to convert the archive link of february2008 back into February 2008.

What I have found is that writing a lot of the code needed to run an effective blogging platform is not particularly complicated when the function needed is broken down into a series of steps.</body>
    <created-at type="datetime">2008-02-28T21:34:08+00:00</created-at>
    <id type="integer">16</id>
    <month-year>February 2008</month-year>
    <published type="boolean">true</published>
    <summary nil="true"></summary>
    <title>Creating monthly archives in Rails</title>
    <updated-at type="datetime">2008-05-18T16:16:41+00:00</updated-at>
  </entry>
  <entry>
    <author>Robin Fisher</author>
    <body>There's not a lot that I can say that hasn't been said already on this subject.  I've managed to get this working tonight via a combination of &lt;a href="http://railstips.org/2007/7/23/autotest-growl-pass-fail-notifications"&gt;John Nunemaker&lt;/a&gt; and &lt;a href="http://blog.aisleten.com/2008/02/21/installing-growlnotify-and-autotest-for-bdd-use-with-rspec-on-leopard/"&gt;Aisle Ten&lt;/a&gt;.

John's blog entry is a great high level overview of how to get it to work and Aisle Ten's post will come in very useful if you run into any problems.</body>
    <created-at type="datetime">2008-03-02T19:08:40+00:00</created-at>
    <id type="integer">17</id>
    <month-year>March 2008</month-year>
    <published type="boolean">true</published>
    <summary nil="true"></summary>
    <title>A little bit on growl and Autotest</title>
    <updated-at type="datetime">2008-05-18T16:16:41+00:00</updated-at>
  </entry>
  <entry>
    <author>Robin Fisher</author>
    <body>&lt;a href="http://2008.dconstruct.org/"&gt;I absolutely love this design for dConstruct 2008&lt;/a&gt;.</body>
    <created-at type="datetime">2008-03-03T15:06:50+00:00</created-at>
    <id type="integer">18</id>
    <month-year>March 2008</month-year>
    <published type="boolean">true</published>
    <summary nil="true"></summary>
    <title>dConstruct 2008</title>
    <updated-at type="datetime">2008-05-18T16:16:41+00:00</updated-at>
  </entry>
  <entry>
    <author>Robin Fisher</author>
    <body>Due to pressing issues at work, I haven't had the chance to say that &lt;a href="http://www.intaeco.co.uk/"&gt;Intaeco&lt;/a&gt; has gone live.

The company sells environmentally friendly plumbing and heating products such as solar heating systems.  The site is static in nature aside from some PHP for the contact form and jQuery is used for the javascript effects.</body>
    <created-at type="datetime">2008-03-09T20:39:25+00:00</created-at>
    <id type="integer">19</id>
    <month-year>March 2008</month-year>
    <published type="boolean">true</published>
    <summary nil="true"></summary>
    <title>Intaeco goes live</title>
    <updated-at type="datetime">2008-05-18T16:16:41+00:00</updated-at>
  </entry>
  <entry>
    <author>Robin Fisher</author>
    <body>EDIT: I have followed this up with a further post, &lt;a href="http://capturedsparks.com/entries/23-more-on-activemerchant-and-paypal"&gt;More on ActiveMerchant and Paypal&lt;/a&gt;.

I've spent most of the past week playing with ActiveMerchant and Paypal in order to implement recurring billing for my app.

After a false start with Datacash and some fumbling in the Paypal Sandbox, I got started with a test account for Website Payments Pro (UK).  This has the benefit of using Paypal as your gateway service and also as your merchant account.  The fees for processing are slightly higher than other gateways but I find the all in one solution worth it so far.

I should mention at this point that &lt;a href="http://peepcode.com/products/activemerchant-pdf"&gt;Cody Fauser's ActiveMerchant PDF&lt;/a&gt; from PeepCode was invaluable in giving me a start to integration.  Although the book is geared towards a straightforward purchase (rather than recurring billing), the code was a great starting point.  Thankfully, the ActiveMerchant library is very well commented and easily understandable.

In brief, to setup the recurring billing (implemented through Subscription model), an account is created using the subdomain as account key model. If the account is a paying account, the user is redirected to a secure page to enter their credit card details and create the subscription. The credit card information, amount to be billed and frequency are passed to Paypal in the following form:

&lt;pre class="brush: ror"&gt;
Subscription.recurring(amount, credit_card, options = {:ip =&gt; request.remote_ip})
&lt;/pre&gt;

This calls a method on the Subscription class which sends the data to Paypal.  If a successful response is received, the response and other information is stored in the database.

In terms of updating the subscription, this is easily done with the AM library by sending the profile id (which is returned by Paypal when recurring billing is set up) along with the recurring billing request.  Using this method, credit card details, payment amount and frequency can be simply changed.

I'm more than happy to share the code I'm using if you want to leave a comment.</body>
    <created-at type="datetime">2008-03-25T21:35:22+00:00</created-at>
    <id type="integer">20</id>
    <month-year>March 2008</month-year>
    <published type="boolean">true</published>
    <summary></summary>
    <title>ActiveMerchant, Paypal and Rails</title>
    <updated-at type="datetime">2009-10-11T14:03:26+00:00</updated-at>
  </entry>
  <entry>
    <author>Robin Fisher</author>
    <body>I haven't had much opportunity to post here recently due to some travel and a mix of work on my own projects and work for clients.  Aside from my development work, I also maintain a few websites and the updates and maintenance for these have been coming thick and fast.

One of my own projects is approaching fruition.  It's a small application that allows people to review coffee shops that are local to them or that they visit.  The idea came following a trip to Hull where I had about 5 hours to kill and there was no way to find details of a good coffee shop where I could spend a few hours.  I suppose I hope it may help unearth some gems and stop people heading for the nearest Starbucks or Costa.

The application uses the Google Maps API and the GeoKit plugin to geocode the location of coffee houses.  I think this is the type of application that really suits having a mobile version and once the web version is sufficiently complete, I'll work on producing a mobile friendly version.  There is quite a bit to do, but I'm going to push it live in the next month and hopefully get some feedback that will drive continued development.

I also hope to write up a bit more detail on ActiveMerchant and PayPal as I note from the logs that the entry on that topic has received quite a bit of traffic and I think it is definitely a topic that could do with more documentation.


</body>
    <created-at type="datetime">2008-05-10T13:26:19+00:00</created-at>
    <id type="integer">21</id>
    <month-year>May 2008</month-year>
    <published type="boolean">true</published>
    <summary nil="true"></summary>
    <title>Busy times</title>
    <updated-at type="datetime">2008-05-18T16:16:41+00:00</updated-at>
  </entry>
  <entry>
    <author>Robin Fisher</author>
    <body>I've spent the past few weeks working a redesign for captured sparks and this weekend, as you can see, I have put it live.

I have also taken the opportunity to implement some functionality that has been missing. As you might know, captured sparks is published on my own system coded in Rails and even though I have had the basics running for a few months, there were some key things that I needed but never found the time to implement.

During the course of the redesign, I've added the following functionality:

&lt;h3&gt;Post Status&lt;/h3&gt;
&lt;p /&gt;I can now classify a post as either a draft or published.

&lt;h3&gt;Comment Administration&lt;/h3&gt;
&lt;p /&gt;Up until now, I have had to manage any comments by logging into the server and directly editing the database through the Rails console. I've now added the ability to approve or reject comments in the admin area.

&lt;p /&gt;I've also made the decision to effectively ignore IE6. The site uses PNGs for titles and I've not taken any steps to address IE6's failure in this regard. Nor have I checked to see how the site looks in IE6 generally. I'm using IE conditional comments to present a friendly warning to those users with IE6 that the site may not look great and suggesting an upgrade.</body>
    <created-at type="datetime">2008-05-18T18:38:23+00:00</created-at>
    <id type="integer">22</id>
    <month-year>May 2008</month-year>
    <published type="boolean">true</published>
    <summary nil="true"></summary>
    <title>A new look</title>
    <updated-at type="datetime">2008-05-18T18:40:34+00:00</updated-at>
  </entry>
  <entry>
    <author>Robin Fisher</author>
    <body>I've had a few comments asking for some more information setting up AM with Paypal. I won't profess to be an expert and there may be better ways of doing this.

I am using Paypal UK Website Payments Pro and for this have set up an account that gives me access to Paypal Manager.

As per my previous post, an account is created using the account key as subdomain model:

&lt;pre class="brush: ror"&gt;
def create
    @account = Account.new(params[:account])
    @account.initial_plan = params[:plan_id]
    if @account.save
      @account.set_admin
      if @account.initial_plan == "2"
        redirect_to :host =&gt; account_host(@account.name), :controller =&gt; 'sessions', :action =&gt; 'new'
      else
        redirect_to :host =&gt; account_host(@account.name), :controller =&gt; 'subscriptions', :action =&gt; 'new'
      end
    else
      flash[:error] = "Could not create account. Please try again."
      redirect_to :controller =&gt; 'accounts', :action =&gt; 'new'
    end
  end
&lt;/pre&gt;

If the customer has selected anything other than a free account, they are redirect to the new action of the subscriptions controller. I am using the subscription model to act as a join between an account and a particular plan.

The template for the new action is a simple form with space for credit card information. Creating a subscription calls the following create action in the controller:

&lt;pre class="brush: ror"&gt;
def create
    @plan = Plan.find_by_id(@account.initial_plan)
    first_name = params[:cc_name].split(' ')[0]
    surname = params[:cc_name].split(' ')[1]
    name = params[:cc_name]
    number = params[:cc_number]
    amount = @plan.price*100
    credit_card = {
      :number     =&gt; "#{number}", 
      :first_name =&gt; "#{first_name}", 
      :last_name  =&gt; "#{surname}",
      :name       =&gt; "#{name}",
      :month      =&gt; "#{params[:cc_month]}", 
      :year       =&gt; "#{params[:cc_year]}",        
      :verification_value =&gt; "#{params[:cc_cvv]}", 
      :type       =&gt; "#{params[:cc_type]}" 
    }
    subscription = Subscription.recurring(amount, credit_card, options = {:ip =&gt; request.remote_ip})
    if subscription
      subscription.plan_id = @plan.id
      subscription.account_id = @account.id
      subscription.save
      flash[:notice] = "Your account has been setup.  You can now login!"
      redirect_to matters_url
    else
      flash[:error] = "YIKES!"
      redirect_to new_subscription_url
    end
  end
&lt;/pre&gt;

I have no doubt that a lot of this could be refactored into the model. At the moment, I am focussing on getting the app running, not tidying up the code. You will note the class method "recurring", which is in the subscription.rb file. The code for this is taken straight from the AM pdf mentioned in my earlier post so I cannot repost that here. This method creates a connection through AM to Paypal and creates a recurring subscription. Information that is returned includes a profile id that can be used to uniquely identify a particular subscription in both the app and Paypal manager.

Updating the subscription is fairly similar to creating a new subscription except you pass the profile id through so that Paypal knows which account to change.

One thing to note is that it is important to ensure consistency between Paypal and the subscriptions table in your app. It is very easy to update a subscription in Paypal so that a customer is billed the correct amount but fail to update the internal record in your app. This will result in revenues being either significantly higher or lower than you expect.

One of the questions in the comments to the original post is how much information in the pdf was relevant to Paypal US. I can't directly answer that but I can say that the code works as a great starting point but some re-coding will necessary to make it work for your app.
</body>
    <created-at type="datetime">2008-05-18T19:02:09+00:00</created-at>
    <id type="integer">23</id>
    <month-year>May 2008</month-year>
    <published type="boolean">true</published>
    <summary></summary>
    <title>More on ActiveMerchant and Paypal</title>
    <updated-at type="datetime">2009-10-11T14:02:25+00:00</updated-at>
  </entry>
  <entry>
    <author>Robin Fisher</author>
    <body>The final 10% is always the hardest bit to do. Unfortunately, it's generally that bit that makes something really work. It stops something being OK and makes it great. It makes you go "Wow".

On my coffee application (I still don't have a name apart from wanna coffee?, which I don't like), the majority of the functionality is there. In its most basic form, the app works. It just doesn't have that polish and that is what I'm talking about. That is the final 10% and I wouldn't be happy launching it without that polish. I'm happy if some areas of functionality are not present at launch, provided they are not core to the purpose.

What I don't want to do is launch at 90% of what I want, and would expect, version 1 to be like. It's that 10% that I'm working on now.</body>
    <created-at type="datetime">2008-05-27T11:53:34+00:00</created-at>
    <id type="integer">24</id>
    <month-year>May 2008</month-year>
    <published type="boolean">true</published>
    <summary nil="true"></summary>
    <title>The final 10%</title>
    <updated-at type="datetime">2008-05-27T11:53:34+00:00</updated-at>
  </entry>
  <entry>
    <author>Robin Fisher</author>
    <body>I'm happy to announce the launch of &lt;a href="http://www.wantbeans.com/"&gt;Want Beans!&lt;/a&gt;

Want Beans is a social network for reviewing and rating coffee shops and finding great places to grab a coffee when you're out and about.

As I mentioned in an earlier post, the idea was inspired when I had about 5 hours to kill in Hull and just wanted to find somewhere to hang out with my MacBook.

I hope that you'll register and add your favourite cafe to help other people discover great places to grab a latte. To get started, please visit &lt;a href="http://www.wantbeans.com/"&gt;Want Beans&lt;/a&gt;.</body>
    <created-at type="datetime">2008-06-08T12:52:20+00:00</created-at>
    <id type="integer">25</id>
    <month-year>June 2008</month-year>
    <published type="boolean">true</published>
    <summary nil="true"></summary>
    <title>Want Beans</title>
    <updated-at type="datetime">2008-06-08T12:53:32+00:00</updated-at>
  </entry>
  <entry>
    <author>Robin Fisher</author>
    <body>I spent the weekend getting a little application to play nicely with emails being sent to it.  As receiving emails with Rails is something that is not written about as much as sending emails, I thought I would share my solution.

This tutorial will show you how to receive emails into your application, store them in the database and forward the contents to multiple recipients.

The first problem of course is getting the emails into your application.  I have root access to my server, so my solution uses Postfix.  If you don't have root access, you can use POP and there are a &lt;a href="http://wiki.rubyonrails.org/rails/pages/HowToReceiveEmailsWithActionMailer"&gt;number&lt;/a&gt; &lt;a href="http://railspikes.com/2007/6/1/rails-email-processing"&gt;of&lt;/a&gt; &lt;a href="http://www.naffis.com/blog/articles/2006/08/14/receiving-emails-and-attachments-with-rails"&gt;examples&lt;/a&gt; out there.  On with the instructions...

As I am hosting a number of domains on the same box, I set up my main.cf file as follows:

&lt;pre class="brush: ror"&gt;
virtual_alias_domains = mydomain.com
virtual_alias_maps = hash:/etc/postfix/virtual
&lt;/pre&gt;

I then set up my virtual file (which you may need to create) with a single line:

&lt;pre class="brush: ror"&gt;
@mydomain.com rails_mailer
&lt;/pre&gt;

This will intercept any emails sent to mydomain.com and pass them to the rails_mailer alias, which is created in your alias file.  Mine is located in /etc/aliases: yours might be in /etc/postfix/aliases.  Add to the bottom of your aliases file:

&lt;pre class="brush: ruby"&gt;
rails_mailer: "|curl -F mail='&lt;-' http://mydomain.com/emails"
&lt;/pre&gt;

This uses curl to post the mail as form data to the given url.  The email contents will be stored inside the mail parameter.  The pipe character at the start indicates that this is a shell command and not a directory.

To apply all these changes:

&lt;pre class="brush: ruby"&gt;
sudo postmap /etc/postfix/virtual
sudo newaliases
sudo /etc/init.d/postfix reload
&lt;/pre&gt;

To check that this is working, change into your /var/log directory and use:

&lt;pre class="brush: ruby"&gt;
tail -f mail.info
&lt;/pre&gt;

Then send an email to any address @mydomain.com and you should see it received in your mail log and passed to your Rails app.  If you look in your app's logs, you should see it spitting out a 500 error as there is no code to handle the email...yet.

On to the Ruby.  Create an Emails controller and define a create method:

&lt;pre class="brush: ruby"&gt;
def create
  if params[:mail]
    Notifier.receive(params[:mail])
  end
end
&lt;/pre&gt;

This receives the contents of params[:mail] and passes it to the receive method of our notifier model.

To deal with Rails' cross-site scripting protection, you need to add to the top of your controller:

&lt;pre class="brush: ror"&gt;
skip_before_filter :verify_authenticity_token
&lt;/pre&gt;

Next, generate a mailer called notifier.  In notifier.rb, define a method called receive(email).  Using this method name automatically invokes the power of &lt;a href="http://tmail.rubyforge.org/"&gt;TMail&lt;/a&gt;.  My receive method is as follows.  You will need to change this to make sure you pull the information you need from the email:

&lt;pre class="brush: ror"&gt;
def receive(email)
  event_name = email.to
  event_name = event_name.to_s.sub('@mydomain.com', '')
  event = Event.find_by_tidy_name(event_name)
  body = email.body
  address = Array.new
  event.attendees.each do |attendee|
    address &lt;&lt; attendee.email.to_s
  end
  from = email.from.to_s
  new_email = event.emails.new
  new_email.from = email.friendly_from
  new_email.body = body
  new_email.save
  Notifier.deliver_event_email(event, from, address, body)
end
&lt;/pre&gt;

Before running through this code, I should explain that when people use the app, they receive a dedicated email address in format myeventname@mydomain.com.

This code does two things.  Firstly, it extracts the following data from the email: the name of the event, the body of the email and who the email is from.  It then constructs a new email that belongs to the event and saves to the database.  It then invokes another method in our notifier.rb to forward the email body to the individuals who are attending the event.

&lt;pre class="brush: ror"&gt;
def event_email(event, from, address, body)
  setup_email(from)
  @bcc = address
  @subject += "#{event.name}"
  @body[:body] = body
end
&lt;/pre&gt;

In terms of the application that I wrote this for, I hope to launch it within the next week.  If you've got any questions or run into any problems, leave a comment and I'll try and help.</body>
    <created-at type="datetime">2008-06-17T08:29:55+00:00</created-at>
    <id type="integer">26</id>
    <month-year>June 2008</month-year>
    <published type="boolean">true</published>
    <summary></summary>
    <title>Receiving emails with Ruby on Rails</title>
    <updated-at type="datetime">2009-10-11T14:01:06+00:00</updated-at>
  </entry>
  <entry>
    <author>Robin Fisher</author>
    <body>I'm pleased to announce the launch of &lt;a href="http://eventamatic.com/"&gt;Eventamatic!&lt;/a&gt;, a simple way for you to manage your events.</body>
    <created-at type="datetime">2008-07-06T17:08:36+00:00</created-at>
    <id type="integer">27</id>
    <month-year>July 2008</month-year>
    <published type="boolean">true</published>
    <summary nil="true"></summary>
    <title>Eventamatic!</title>
    <updated-at type="datetime">2008-07-06T17:22:14+00:00</updated-at>
  </entry>
  <entry>
    <author>Robin Fisher</author>
    <body>&lt;a href="http://www.37signals.com/"&gt;37signals&lt;/a&gt;, who are perhaps best known for Basecamp, have just posted &lt;a href="http://www.37signals.com/svn/posts/1125-the-early-days-how-37signals-built-buzz-out-of-the-gate"&gt;an interesting blog post&lt;/a&gt; on how they built buzz in their early days. It's a great look back at the origins of a company that now inspires a lot of other web design and web application companies. Not just in terms of the work they produce, but also in terms of their approach to running a business.

What the post highlights is how it is not always necessary to focus on what you do provided that the things you are doing are related to your primary activity. Ideas like the E-Commerce Search Report and Design Not Found offer an "in" to prospective customers.

I also subscribe to &lt;a href="http://sethgodin.typepad.com/"&gt;Seth Godin&lt;/a&gt; and one of the ideas he promotes is to always offer content. Seth has a new post on his blog every day (or thereabouts).

It takes a concerted effort to build buzz and drive business. The posts here at captured sparks have always been a little sparse, and mainly related to web development. From now, I will be making a concerted effort to post more.</body>
    <created-at type="datetime">2008-07-14T21:35:27+00:00</created-at>
    <id type="integer">28</id>
    <month-year>July 2008</month-year>
    <published type="boolean">true</published>
    <summary nil="true"></summary>
    <title>Building Buzz</title>
    <updated-at type="datetime">2008-07-14T21:35:27+00:00</updated-at>
  </entry>
  <entry>
    <author>Robin Fisher</author>
    <body>I was at a meeting a couple of days ago and somebody raised a question about empowerment for the employees. They seemed to be looking for an indication from our CFO that they would be empowered to, and entitled to, make decisions without having to refer it to a manager.

I found the question extremely strange as I have always considered the company for which I work to delegate a lot of responsibility to the employees. I have never felt constrained or not permitted to make a decision and thought it odd that a colleague did.

One of the things I do find is that people often shirk that responsibility. They ask for it. They want it. They want to feel that the company trusts them to do the right thing. But they don't actually want to take action. They are too scared of making the wrong decision.

When recruiting people, I'm always interested in finding out how they respond to that kind of empowerment. I ask them for an example of when they took a wrong decision at work and how they coped with the consequences. Did it deter them from making further decisions?

Giving people the power to make decisions is half the battle. Creating a culture where people feel secure in actually making them is the other half. Where they don't think they will get fired if it goes wrong. Where genuinely acting in the best interests of the company is the important thing.
</body>
    <created-at type="datetime">2008-08-07T20:12:59+00:00</created-at>
    <id type="integer">29</id>
    <month-year>August 2008</month-year>
    <published type="boolean">true</published>
    <summary nil="true"></summary>
    <title>Empowerment</title>
    <updated-at type="datetime">2008-08-07T20:13:00+00:00</updated-at>
  </entry>
  <entry>
    <author>Robin Fisher</author>
    <body>You no longer need to create an account to create a cafe on Want Beans. Add your favourite coffee house by visiting &lt;a href="http://wantbeans.com/cafes/new"&gt;the new cafe page&lt;/a&gt;.</body>
    <created-at type="datetime">2008-08-07T20:25:25+00:00</created-at>
    <id type="integer">30</id>
    <month-year>August 2008</month-year>
    <published type="boolean">true</published>
    <summary nil="true"></summary>
    <title>Want Beans Update</title>
    <updated-at type="datetime">2008-08-07T20:25:25+00:00</updated-at>
  </entry>
  <entry>
    <author>Robin Fisher</author>
    <body>One of the common issues that has plagued web designers is how to ensure that a sidebar column with a background colour will fill the height of the page when a second column is much longer. One of the most used options is &lt;a href="http://www.alistapart.com/articles/fauxcolumns/"&gt; Faux Columns&lt;/a&gt; by &lt;a href="http://www.simplebits.com/"&gt;Dan Cederholm&lt;/a&gt;.

I'm going to show you how to quickly achieve identical height columns using jQuery.

We start with a simple layout:

&lt;pre class="brush: xhtml"&gt;
&lt;div id="main"&gt;
  &lt;div id="sidebar"&gt;
     Lorem ipsum..
  &lt;/div&gt;

  &lt;div id="content"&gt;
    Lorem ipsum...
  &lt;/div&gt;
&lt;/div&gt;
&lt;/pre&gt;

We can then use the following jQuery code to ensure that the sidebar is always equal to the height of the content column:

&lt;pre class="brush: javascript"&gt;
var mainHeight = jQuery('#main').height();
  if (mainHeight &gt; 280) {
    jQuery('#sidebar').css({
      height: mainHeight
    });
  } else { 
  };
&lt;/pre&gt;

This grabs the height of the #main div and if that height is greater than 280px, dynamically adjusts the height of the sidebar to match.





</body>
    <created-at type="datetime">2008-08-17T11:46:34+00:00</created-at>
    <id type="integer">31</id>
    <month-year>August 2008</month-year>
    <published type="boolean">true</published>
    <summary></summary>
    <title>Equal height columns</title>
    <updated-at type="datetime">2009-10-11T13:57:31+00:00</updated-at>
  </entry>
  <entry>
    <author>Robin Fisher</author>
    <body>So, my last entry here was 17th August 2008. And that was written just over a month after I said I would post more. Work took over. My full-time job was incredibly busy during the last 3 months of 2008 and the I have been working on a Rails site since October and that is still ongoing. As a result of this combination, I never really had the opportunity to post anything to the blog.

For me, 2008 was a good year.  During 2007, my site received 200 visits. In 2008, it received over 1700 visits. This was driven primarily by three articles I wrote on 2 subjects - combining ActiveMerchant and Paypal (something I still receive emails about) and receiving emails with Rails. The visitor numbers have kept up through January 2009 and I hope to post more this year to drive more traffic.

The site I'm working on at the moment is a straight-forward brochure site although I have done a nice implementation with Google Maps to show the nearest stockists for the products sold by the client.  This should be finished within the next month, following which I hope to work on a small project of my own. Nothing concrete as yet but have some ideas floating round my head.

Finally, I've been spammed massively in the comments. If you left a comment after 16 January, I'm afraid I've had to delete it as I couldn't go through 2000 comments to identify the genuine ones.  Sorry again.

 </body>
    <created-at type="datetime">2009-02-15T18:39:30+00:00</created-at>
    <id type="integer">32</id>
    <month-year>February 2009</month-year>
    <published type="boolean">true</published>
    <summary>So, my last entry here was 17th August 2008. And that was written just over a month after I said I would post more. Work took over.</summary>
    <title>Update!</title>
    <updated-at type="datetime">2009-02-15T18:39:30+00:00</updated-at>
  </entry>
  <entry>
    <author>Robin Fisher</author>
    <body>So, I'm back. And with a refresh.

In the 8 months since my last posting, I've worked on &lt;a href="http://www.intatec.co.uk/"&gt; another site&lt;/a&gt; and done a lot of work at my day job.

I have a couple of posts lined up web design on bits and pieces that I've noticed recently and I'm considering doing a beginner's series on Ruby on Rails but want to make sure I have a plan for it first.

Good to be back.</body>
    <created-at type="datetime">2009-10-10T16:31:02+00:00</created-at>
    <id type="integer">33</id>
    <month-year>October 2009</month-year>
    <published type="boolean">true</published>
    <summary>So, I'm back. And with a refresh.</summary>
    <title>Back</title>
    <updated-at type="datetime">2009-10-10T16:35:01+00:00</updated-at>
  </entry>
  <entry>
    <author>Robin Fisher</author>
    <body>When redesigning captured sparks, I made the conscious decision to design for the latest browsers. This was for 2 reasons: Firstly, it reduced the amount of time I needed to spend testing the site - an entirely selfish reason, I accept. Secondly, the only way to drive a reduction in the number of users with older browsers, is for more developers and designers to design sites using the latest technology.

I accept, of course, that a significant number of users in corporate environments may have no control over their browser of choice. For this, I do plan on offering "a simple version":http://stuffandnonsense.co.uk/blog/about/universal_internet_explorer_6_css/ of captured sparks.

In light of this, I have not had regard to compatibility with older browsers such as "Internet Explorer 6":http://www.bringdownie6.com/.  The main feature, unsupported by older browsers, that this site makes use of is the @font-face construct.  Headings on the site use the "Contra":http://www.fontsquirrel.com/fonts/Contra font, with degradation to Georgia etc.

I also make liberal use of some other CSS3 properties:

&lt;pre class="brush: css"&gt;
border-radius: 5px;
box-shadow: 2px 2px 10px #222;
&lt;/pre&gt;

I'm also using a Safari only property to handle the fades on the "Work":http://capturedsparks.com/jobs page:

&lt;pre class="brush: css"&gt;
-webkit-transition: opacity 0.7s linear;
&lt;/pre&gt;

Given that I use this site to try and secure work, it may not be the best illustration of how I can make a site cross-browser compatible. However, in these circumstances, I hope potential clients will "look at my other work":http://capturedsparks.com/jobs and see that for paid work, cross-browser compatibility is something I do strive for.</body>
    <created-at type="datetime">2009-10-12T19:43:50+00:00</created-at>
    <id type="integer">34</id>
    <month-year>October 2009</month-year>
    <published type="boolean">true</published>
    <summary>When redesigning captured sparks, I made the conscious decision to design for the latest browsers.</summary>
    <title>Design Decisions</title>
    <updated-at type="datetime">2009-10-12T19:49:36+00:00</updated-at>
  </entry>
  <entry>
    <author>Robin Fisher</author>
    <body>I've spent the weekend creating "my first gem release":http://github.com/robinjfisher/trim-api, version 0.0.1 of which is "now available":http://gemcutter.org/gems/trim-api.

The purpose of the gem is to provide a wrapper around the "tr.im api":http://tr.im/website/api. At the moment, it only supports the ability to trim a larger url down to size. I found this to be a good introduction to working with an API as no authentication is required for this basic functionality. Over time, I intend to add in the other functionality supported by the API.

Following Github's decision to not support the creation of new gems, the gem is stored at http://gemcutter.org/. To install, you will need to do the following:

&lt;pre class="brush: ruby"&gt;
gem sources -a http://gemcutter.org/
gem install trim-api
&lt;/pre&gt;

I hope it is of use.</body>
    <created-at type="datetime">2009-10-18T20:53:52+00:00</created-at>
    <id type="integer">35</id>
    <month-year>October 2009</month-year>
    <published type="boolean">true</published>
    <summary>I've spent the weekend creating my first gem release, version 0.0.1 of which is now available.</summary>
    <title>A ruby wrapper for tr.im</title>
    <updated-at type="datetime">2009-10-18T20:53:52+00:00</updated-at>
  </entry>
  <entry>
    <author>Robin Fisher</author>
    <body>&lt;img src="../images/aviva.png" alt="screenshot of aviva password recovery screen" /&gt;

The first thing is the security question. I can't remember ever telling Aviva the name of the first street I lived on but will assume for these purposes that I did. The street name consisted of 7 letters and then 5 letters: let's say Putting Green.

The first problem is of course encountered when entering the 13th letter. To make it work, the space needs to be included. This then presents the second problem; the 8th letter would be the space. It is easy enough to remove the space when creating the security question but no security question should allow the user to enter a string with spaces when you're asking for specific letters.

The second issue is that the statement, "Not sure of your answer&gt;&gt;", which one assumes to be a link, is not a link.

I was viewing this in Safari 4, so I'm not sure what they are doing with the password hint box. Perhaps it works fine in IE.

Finally, and it is not demonstrated on the screenshot, the cursor retains its default setting when hovering over the continue and back links. It should of course change to pointer so that user expectations are met when hovering a link.

As a result of this, my account ended up being locked. Despite an online request for somebody to contact me to fix it, I've had no response. I gave up waiting in their phone queue after 15 minutes.

One would hope that large companies could avoid such basic errors, particularly when the service is marketed as an online service. Access to all policy documents is via the online portal so it is a fundamental part of their service.</body>
    <created-at type="datetime">2009-10-27T19:07:09+00:00</created-at>
    <id type="integer">39</id>
    <month-year>October 2009</month-year>
    <published type="boolean">true</published>
    <summary>Having just struggled through the password recovery feature on the Aviva website, I wanted to look at what is wrong on only one stage of the process.</summary>
    <title>How do Aviva get it so wrong?</title>
    <updated-at type="datetime">2009-10-27T19:08:40+00:00</updated-at>
  </entry>
  <entry>
    <author>Robin Fisher</author>
    <body>For an application, I'm working on, I needed to associate an aircraft to an airport. The "airport database":http://www.partow.net/miscellaneous/airportdatabase/ I'm using has about 10000 entries so using a select box was impractical.

I looked at some autocomplete plugins but none of them seemed to do what I wanted so I decided to make my own. The solution had to take a string entered by the user and return a list of airports containing that string; display the list of airports, then fill the text box when a user clicks on the airport name. This is how I did it:

&lt;pre class="brush:jscript"&gt;
new Form.Element.Observer('plane_airport_id', 0.1, function(event) {
  var string = $F('plane_airport_id');
    if (string.length &gt;= 3) {
&lt;/pre&gt;

This sets up an observer on the appropriate form field, captures the value and, if the length of the input is greater than or equal to three characters, executes the next part of the script.

&lt;pre class="brush:jscript"&gt;
      new Ajax.Request('/airports', {method:'get',parameters:{search:string},
        onSuccess: function(transport) {
          var airports = transport.responseJSON;
&lt;/pre&gt;

We then setup an XHR(XmlHttpRequest) to the index method of our airports controller, passing the field value as the search parameter. When the call returns successfully, we pass the returned data into the airports variable.

&lt;pre class="brush:jscript"&gt;
          var lis = $('airport-list').descendants();
          if (lis.length &gt; 0) {
            lis.each(function(l) {
              l.remove();
            });
          };
&lt;/pre&gt;

This removes any existing airports in the airport list.

&lt;pre class="brush:jscript"&gt;
          airports.each(function(a) {
            var item = "&lt;li class='airport'&gt;&lt;a href='javascript:;' class='airport-link'&gt;" + a + "&lt;/a&gt;&lt;/li&gt;";
            $('airport-list').insert(item);
          });
          $$('.airport-link').each(function(a) {
            a.observe("click", function() {
              var text = $(this).innerHTML;
              Form.Element.setValue('plane_airport_id',text);
            });
          });
&lt;/pre&gt;

Finally, we take each returned airport, enclose it in list item and anchor tags, and insert each into the unordered list element already in the page. We attach an observer to each anchor tag, so that when it is clicked, it will update the field with the appropriate value. The remaining open brackets are closed accordingly.

The index action in the airports controller is fairly straightforward:

&lt;pre class="brush:ruby"&gt;
def index
  search = params[:search]
  airports = Airport.find(:all, :conditions =&gt; ['name LIKE ?', "%"+search+"%"])
  @airports = Array.new
  airports.each do |a|
    @airports &lt;&lt; "#{capitalize_all(a.name)}, #{capitalize_all(a.country)} (#{a.icao})"
  end
  render :json =&gt; @airports.to_json
end
&lt;/pre&gt;

As the form passes the airport as a string value, when creating an aircraft, I use a regex to extract the ICAO identifier from the string, lookup the corresponding airport and manually update the association column for the aircraft.

The entire javascript code is available as a "gist":http://gist.github.com/230253. 

</body>
    <created-at type="datetime">2009-11-09T20:31:10+00:00</created-at>
    <id type="integer">40</id>
    <month-year>November 2009</month-year>
    <published type="boolean">true</published>
    <summary>How to roll your own autocomplete with Rails and Prototype.</summary>
    <title>Autocomplete with Rails and Prototype</title>
    <updated-at type="datetime">2009-11-09T20:33:59+00:00</updated-at>
  </entry>
  <entry>
    <author>Robin Fisher</author>
    <body>2009 ended on a high note for me. A &lt;a href="http://www.intatec.co.uk"&gt;site I designed in&lt;/a&gt; 2009 for a medium-sized company obtained a really positive review in &lt;a href="http://www.virtualaardvark.com/files/WEBDRAUG09.pdf"&gt;this magazine&lt;/a&gt; (pdf).

&lt;blockquote&gt;Beautifully and simply laid out from start to finish, the home page with its Need Help? and Downloads section front and centre shows this site has a true sense of targeted purpose.&lt;/blockquote&gt;

In terms of statistics, I had just over 2700 visits in 2009, up a 1000 over 2008.

What are my plans for 2010? After some reflection, I think I'm a starter, not a finisher. Looking through the Code folder on my Macbook lists the following project names:

&lt;ul&gt;
&lt;li&gt;coffee&lt;/li&gt;
&lt;li&gt;deliver&lt;/li&gt;
&lt;li&gt;eventamatic&lt;/li&gt;
&lt;li&gt;plane&lt;/li&gt;
&lt;li&gt;radar&lt;/li&gt;
&lt;li&gt;recruit&lt;/li&gt;
&lt;/ul&gt;

All projects in varying stages of completion. For 2010, I want to develop a personal project and have it launched and mildly successful. For this, I'd be happy to partner with anyone who is looking to do the same.  I am of course also available for client work.

I wish everyone a successful and happy 2010.</body>
    <created-at type="datetime">2010-01-08T19:14:43+00:00</created-at>
    <id type="integer">41</id>
    <month-year>January 2010</month-year>
    <published type="boolean">true</published>
    <summary>A look back at 2009.</summary>
    <title>Another year has been and gone</title>
    <updated-at type="datetime">2010-01-08T19:14:43+00:00</updated-at>
  </entry>
</entries>
