<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">
  <channel>
    <title>random utterings...</title>
    <link>http://blog.randomutterings.com</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description />
    <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/randomutterings/blog" /><feedburner:info uri="randomutterings/blog" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
      <title>Centralized multi-deployment approach with Capistrano </title>
      <description>&lt;style&gt;
.note {
  background-color: #f1f1f1;
  font-size: 15px;
  padding: 8px;
  margin-left: 70px;
  margin-right: 70px;
}
&lt;/style&gt;

&lt;p&gt;Capistrano is most often used for deploying a single Rails application but with a few libraries you can use it to deploy multiple applications or “services” in a service oriented architecture.  In this article we’ll walk through how to build this type of deployment application with Capistrano.&lt;/p&gt;

&lt;p&gt;From the docs:&lt;/p&gt;

&lt;p class="note"&gt;Capistrano is a utility and framework for executing commands in parallel on multiple remote machines, via SSH. It uses a simple DSL (borrowed in part from Rake) that allows you to define tasks, which may be applied to machines in certain roles. It also supports tunneling connections via some gateway machine to allow operations to be performed behind VPN's and firewalls.&lt;/p&gt;

&lt;p&gt;Normally with Capistrano your deployment code lives in the application repository.  With multiple applications or services, there would be serious disadvantages to this approach.  With a centralized deployment application, all of our deployment code is located in single repository.  We can easily refactor it, secure it, and it's DRY.&lt;/p&gt;

&lt;p&gt;Since Capistrano executes remote commands via SSH, user restrictions inside the deployment application shouldn’t be necessary.  Individuals who have the permissions needed for a particular environment (production, qa, staging, etc) will be able to deploy to that environment.  Additionally, you can restrict access to the deployment application repository so only specific people/departments have access to update the deployment application code.&lt;/p&gt;

&lt;p&gt;Here's an example of a directory structure for deploying 3 services in an SOA application.&lt;/p&gt;
&lt;pre&gt;
├── config
│   ├── deploy
│   │   ├── soa_app
│   │   │   ├── core_service
│   │   │   │   ├── production.rb
│   │   │   │   └── qa.rb
│   │   │   │   └── staging.rb
│   │   │   ├── user_service
│   │   │   │   ├── production.rb
│   │   │   │   └── qa.rb
│   │   │   │   └── staging.rb
│   │   │   └── billing_service
│   │   │       ├── production.rb
│   │   │       └── qa.rb
│   │   │       └── staging.rb
│   │   └── global.rb
│   └── deploy.rb
├── recipes
├── Capfile
└── Gemfile
&lt;/pre&gt;

&lt;p&gt;You can create this structure manually or use a gem called CapHub which will generate the basic directory structure for you and install some needed gems.  It will also install a couple that are out of scope for this article so we'll build the structure manually.&lt;/p&gt;

&lt;p&gt;Add the following to your Gemfile&lt;/p&gt;

&lt;pre style='color:#d1d1d1;background:#000000;'&gt;
&lt;span style='color:#e66170; font-weight:bold; '&gt;source &lt;/span&gt;&lt;span style='color:#00c4c4; '&gt;"https://rubygems.org"&lt;/span&gt;

&lt;span style='color:#9999a9; '&gt;# Required: allows us to specify a separate configuration for each application/service&lt;/span&gt;
gem &lt;span style='color:#00c4c4; '&gt;"capistrano-multiconfig"&lt;/span&gt;

&lt;span style='color:#9999a9; '&gt;# Optional: confirm deployment tasks if the local deployment application is not up to date&lt;/span&gt;
gem &lt;span style='color:#00c4c4; '&gt;"capistrano-uptodate"&lt;/span&gt;     

&lt;span style='color:#9999a9; '&gt;# Optional: use rvm to install and manage RVM and Rubies remotely&lt;/span&gt;
gem &lt;span style='color:#00c4c4; '&gt;"rvm-capistrano"&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Add the following to your Capfile&lt;/p&gt;

&lt;pre style='color:#d1d1d1;background:#000000;'&gt;
&lt;span style='color:#e66170; font-weight:bold; '&gt;require&lt;/span&gt; &lt;span style='color:#00c4c4; '&gt;'capistrano/multiconfig'&lt;/span&gt;
&lt;span style='color:#e66170; font-weight:bold; '&gt;require&lt;/span&gt; &lt;span style='color:#00c4c4; '&gt;'capistrano/uptodate'&lt;/span&gt;
&lt;span style='color:#e66170; font-weight:bold; '&gt;require&lt;/span&gt; &lt;span style='color:#00c4c4; '&gt;'rvm/capistrano'&lt;/span&gt;

&lt;span style='color:#9999a9; '&gt;# Optional: Use bundler for managing remote gems&lt;/span&gt;
&lt;span style='color:#e66170; font-weight:bold; '&gt;require&lt;/span&gt; &lt;span style='color:#00c4c4; '&gt;'bundler/capistrano'&lt;/span&gt;

&lt;span style='color:#9999a9; '&gt;# Load capistrano's deploy recipes&lt;/span&gt;
&lt;span style='color:#e66170; font-weight:bold; '&gt;load&lt;/span&gt; &lt;span style='color:#00c4c4; '&gt;'deploy'&lt;/span&gt;
&lt;span style='color:#e66170; font-weight:bold; '&gt;load&lt;/span&gt; &lt;span style='color:#00c4c4; '&gt;'deploy/assets'&lt;/span&gt;

&lt;span style='color:#9999a9; '&gt;# Load all custom recipes&lt;/span&gt;
Dir&lt;span style='color:#d2cd86; '&gt;[&lt;/span&gt;&lt;span style='color:#00c4c4; '&gt;'recipes/**/*.rb'&lt;/span&gt;&lt;span style='color:#d2cd86; '&gt;]&lt;/span&gt;&lt;span style='color:#d2cd86; '&gt;.&lt;/span&gt;&lt;span style='color:#e66170; font-weight:bold; '&gt;each&lt;/span&gt; &lt;span style='color:#b060b0; '&gt;{&lt;/span&gt; |recipe| &lt;span style='color:#e66170; font-weight:bold; '&gt;load&lt;/span&gt;&lt;span style='color:#d2cd86; '&gt;(&lt;/span&gt;recipe&lt;span style='color:#d2cd86; '&gt;)&lt;/span&gt; &lt;span style='color:#b060b0; '&gt;}&lt;/span&gt;

&lt;span style='color:#9999a9; '&gt;# Load common configuration&lt;/span&gt;
&lt;span style='color:#e66170; font-weight:bold; '&gt;load&lt;/span&gt; &lt;span style='color:#00c4c4; '&gt;'config/global'&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;The core functionality of our deployment application is in capistrano-multiconfig. It automatically builds Capistrano configurations from files located in config/deploy so creating config/deploy/soa_app/user_service/production.rb will make the corresponding configuration task available:&lt;/p&gt;
&lt;pre&gt;
  $ cap -T
  ...
  cap soa_app:user_service:production     # Load soa_app:user_service:production configuration
  ...
&lt;/pre&gt;

&lt;p&gt;Let's take a look at our common configuration.&lt;/p&gt;

&lt;pre style='color:#d1d1d1;background:#000000;'&gt;
&lt;span style='color:#9999a9; '&gt;# config/global.rb&lt;/span&gt;
&lt;span style='color:#9999a9; '&gt;# Put configuration here that is shared between ALL applications to be deployed&lt;/span&gt;

&lt;span style='color:#9999a9; '&gt;# some global defaults, yours may differ&lt;/span&gt;
set :rvm_ruby_string, &lt;span style='color:#00c4c4; '&gt;'1.9.3'&lt;/span&gt;
set :scm, :git
set :scm_verbose, &lt;span style='color:#e66170; font-weight:bold; '&gt;true&lt;/span&gt;
set :user, &lt;span style='color:#00c4c4; '&gt;'bob'&lt;/span&gt;
ssh_options&lt;span style='color:#d2cd86; '&gt;[&lt;/span&gt;:keys&lt;span style='color:#d2cd86; '&gt;]&lt;/span&gt; &lt;span style='color:#d2cd86; '&gt;=&lt;/span&gt; &lt;span style='color:#d2cd86; '&gt;[&lt;/span&gt;File&lt;span style='color:#d2cd86; '&gt;.&lt;/span&gt;join&lt;span style='color:#d2cd86; '&gt;(&lt;/span&gt;ENV&lt;span style='color:#d2cd86; '&gt;[&lt;/span&gt;&lt;span style='color:#00c4c4; '&gt;"HOME"&lt;/span&gt;&lt;span style='color:#d2cd86; '&gt;]&lt;/span&gt;, &lt;span style='color:#00c4c4; '&gt;".ssh"&lt;/span&gt;, &lt;span style='color:#00c4c4; '&gt;"id_rsa"&lt;/span&gt;&lt;span style='color:#d2cd86; '&gt;)&lt;/span&gt;&lt;span style='color:#d2cd86; '&gt;]&lt;/span&gt;
set :git_enable_submodules, &lt;span style='color:#008c00; '&gt;1&lt;/span&gt;

&lt;span style='color:#9999a9; '&gt;# keeps a cached copy of the application repo on each environment for faster deployments&lt;/span&gt;
set :deploy_via, :remote_cache

&lt;span style='color:#9999a9; '&gt;# set the application/service name and rails environment from the task naming convention&lt;/span&gt;
set&lt;span style='color:#d2cd86; '&gt;(&lt;/span&gt;:application&lt;span style='color:#d2cd86; '&gt;)&lt;/span&gt; &lt;span style='color:#b060b0; '&gt;{&lt;/span&gt; config_name&lt;span style='color:#d2cd86; '&gt;.&lt;/span&gt;&lt;span style='color:#e66170; font-weight:bold; '&gt;split&lt;/span&gt;&lt;span style='color:#d2cd86; '&gt;(&lt;/span&gt;&lt;span style='color:#00c4c4; '&gt;':'&lt;/span&gt;&lt;span style='color:#d2cd86; '&gt;)&lt;/span&gt;&lt;span style='color:#d2cd86; '&gt;.&lt;/span&gt;reverse&lt;span style='color:#d2cd86; '&gt;[&lt;/span&gt;&lt;span style='color:#008c00; '&gt;1&lt;/span&gt;&lt;span style='color:#d2cd86; '&gt;]&lt;/span&gt; &lt;span style='color:#b060b0; '&gt;}&lt;/span&gt;    &lt;span style='color:#9999a9; '&gt;# core_service, user_service, billing_service&lt;/span&gt;
set&lt;span style='color:#d2cd86; '&gt;(&lt;/span&gt;:stage&lt;span style='color:#d2cd86; '&gt;)&lt;/span&gt; &lt;span style='color:#b060b0; '&gt;{&lt;/span&gt; config_name&lt;span style='color:#d2cd86; '&gt;.&lt;/span&gt;&lt;span style='color:#e66170; font-weight:bold; '&gt;split&lt;/span&gt;&lt;span style='color:#d2cd86; '&gt;(&lt;/span&gt;&lt;span style='color:#00c4c4; '&gt;':'&lt;/span&gt;&lt;span style='color:#d2cd86; '&gt;)&lt;/span&gt;&lt;span style='color:#d2cd86; '&gt;.&lt;/span&gt;last &lt;span style='color:#b060b0; '&gt;}&lt;/span&gt;                &lt;span style='color:#9999a9; '&gt;# production, qa, staging&lt;/span&gt;
set&lt;span style='color:#d2cd86; '&gt;(&lt;/span&gt;:rails_env&lt;span style='color:#d2cd86; '&gt;)&lt;/span&gt; &lt;span style='color:#b060b0; '&gt;{&lt;/span&gt; stage &lt;span style='color:#b060b0; '&gt;}&lt;/span&gt;
  
&lt;span style='color:#9999a9; '&gt;# we're deploying our database and server config also&lt;/span&gt;
before &lt;span style='color:#00c4c4; '&gt;'deploy:finalize_update'&lt;/span&gt;, &lt;span style='color:#00c4c4; '&gt;'deploy:symlink_database_config'&lt;/span&gt;, &lt;span style='color:#00c4c4; '&gt;'deploy:symlink_apache_config'&lt;/span&gt;

after&lt;span style='color:#d2cd86; '&gt;(&lt;/span&gt;:deploy&lt;span style='color:#d2cd86; '&gt;)&lt;/span&gt; &lt;span style='color:#e66170; font-weight:bold; '&gt;do&lt;/span&gt;
  deploy&lt;span style='color:#d2cd86; '&gt;.&lt;/span&gt;migrate        &lt;span style='color:#9999a9; '&gt;# migrate the database&lt;/span&gt;
  deploy&lt;span style='color:#d2cd86; '&gt;.&lt;/span&gt;cleanup        &lt;span style='color:#9999a9; '&gt;# keep only the last 5 releases&lt;/span&gt;
&lt;span style='color:#e66170; font-weight:bold; '&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Notice we're deploying server configuration as well as application code.  This is optional of course but I like the approach.  We're managing server configuration for each service in a git submodule called &amp;#8249;service-name&amp;#8250;-config.  As configuration changes are introduced we track them in version control and we can test them against our staging environment.  Each release of the service knows the commit reference it should pull from its config repo.  Server configuration management (with rollback) is now part of our deployment strategy.  We get access management for sensitive server configs built in and we can perform automated testing for configuration changes.&lt;/p&gt;

&lt;p&gt;Anything that doesn't apply globally can be specified in individual environment configurations.  Here's an example production configuration for the user_service.&lt;/p&gt;

&lt;pre style='color:#d1d1d1;background:#000000;'&gt;
&lt;span style='color:#9999a9; '&gt;# config/deploy/soa_app/user_service/production.rb&lt;/span&gt;
set :domain, &lt;span style='color:#00c4c4; '&gt;'users.soa_app.com'&lt;/span&gt;
role :web, domain
role :app, domain
role :db,  domain, :primary &lt;span style='color:#d2cd86; '&gt;=&lt;/span&gt;&gt; &lt;span style='color:#e66170; font-weight:bold; '&gt;true&lt;/span&gt;
set :repository,  &lt;span style='color:#00c4c4; '&gt;"git@github.com:bobs-code/user_service.git"&lt;/span&gt;
  
&lt;span style='color:#9999a9; '&gt;# ask for a branch or tag to deploy for the user_service&lt;/span&gt;
&lt;span style='color:#9999a9; '&gt;# make sure to, git push origin --tags, first if you wish to deploy a tag&lt;/span&gt;
set :branch &lt;span style='color:#e66170; font-weight:bold; '&gt;do&lt;/span&gt;
  branch &lt;span style='color:#d2cd86; '&gt;=&lt;/span&gt; ENV&lt;span style='color:#d2cd86; '&gt;[&lt;/span&gt;&lt;span style='color:#00c4c4; '&gt;'BRANCH'&lt;/span&gt;&lt;span style='color:#d2cd86; '&gt;]&lt;/span&gt; || ENV&lt;span style='color:#d2cd86; '&gt;[&lt;/span&gt;&lt;span style='color:#00c4c4; '&gt;'TAG'&lt;/span&gt;&lt;span style='color:#d2cd86; '&gt;]&lt;/span&gt;
&lt;span style='color:#e66170; font-weight:bold; '&gt;&amp;#xa0;&amp;#xa0;if&lt;/span&gt; branch&lt;span style='color:#d2cd86; '&gt;.&lt;/span&gt;&lt;span style='color:#e66170; font-weight:bold; '&gt;nil&lt;/span&gt;?
    Capistrano::CLI&lt;span style='color:#d2cd86; '&gt;.&lt;/span&gt;ui&lt;span style='color:#d2cd86; '&gt;.&lt;/span&gt;ask &lt;span style='color:#00c4c4; '&gt;"Branch or Tag to deploy for the user service: "&lt;/span&gt;
  &lt;span style='color:#e66170; font-weight:bold; '&gt;else&lt;/span&gt;
    branch
  &lt;span style='color:#e66170; font-weight:bold; '&gt;end&lt;/span&gt;
&lt;span style='color:#e66170; font-weight:bold; '&gt;end&lt;/span&gt;
set :deploy_to,   &lt;span style='color:#00c4c4; '&gt;"/home/bob/#{application}-#{stage}"&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;You can override Capistrano’s default deploy tasks or write your own from scratch.  In our example application we're going to mostly depend on Capistrano's deploy task.  We'll override the restart task for our environment and add tasks to symlink our database and apache configurations.&lt;/p&gt;

&lt;pre style='color:#d1d1d1;background:#000000;'&gt;namespace :deploy &lt;span style='color:#e66170; font-weight:bold; '&gt;do&lt;/span&gt;
  desc &lt;span style='color:#00c4c4; '&gt;"Symlink apache config"&lt;/span&gt;
  task :symlink_apache_config &lt;span style='color:#e66170; font-weight:bold; '&gt;do&lt;/span&gt;
    run &lt;span style='color:#00c4c4; '&gt;"sudo ln -nfs #{release_path}/config/submodule/apache/#{application}-#{stage} /etc/apache2/sites-enabled/#{application}-#{stage}"&lt;/span&gt;
  &lt;span style='color:#e66170; font-weight:bold; '&gt;end&lt;/span&gt;

  desc &lt;span style='color:#00c4c4; '&gt;"Restart apache"&lt;/span&gt;
  task :restart &lt;span style='color:#e66170; font-weight:bold; '&gt;do&lt;/span&gt;
    run &lt;span style='color:#00c4c4; '&gt;"sudo /etc/init.d/apache2 restart"&lt;/span&gt;
  &lt;span style='color:#e66170; font-weight:bold; '&gt;end&lt;/span&gt;
&lt;span style='color:#e66170; font-weight:bold; '&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;To deploy our user_service we can execute&lt;/p&gt;
&lt;pre&gt;$ cap soa_app:user_service:production deploy&lt;/pre&gt;

&lt;p&gt;First time deployments to new servers will require some remote directory setup&lt;/p&gt;
&lt;pre&gt;$ cap soa_app:user_service:production deploy:setup&lt;/pre&gt;

&lt;p&gt;Deploying individual services one by one would be time consuming and error prone so we’ll need a way to deploy multiple services simultaneously.  There is a caveat here, since configurations are actually tasks to Capistrano, we must be careful not to run them in parallel or they'll be merged.  To deploy our entire application you could script the deployment tasks in sequence but let's create an additional recipe to handle this instead.&lt;/p&gt;

&lt;pre style='color:#d1d1d1;background:#000000;'&gt;namespace :deploy_all &lt;span style='color:#e66170; font-weight:bold; '&gt;do&lt;/span&gt;
 &lt;span style='color:#d2cd86; '&gt;.&lt;/span&gt;&lt;span style='color:#d2cd86; '&gt;.&lt;/span&gt;&lt;span style='color:#d2cd86; '&gt;.&lt;/span&gt;
 task :staging &lt;span style='color:#e66170; font-weight:bold; '&gt;do&lt;/span&gt;
   Capistrano::CLI&lt;span style='color:#d2cd86; '&gt;.&lt;/span&gt;ui&lt;span style='color:#d2cd86; '&gt;.&lt;/span&gt;say &lt;span style='color:#00c4c4; '&gt;"deploying core_service:staging"&lt;/span&gt;
   &lt;span style='color:#e66170; font-weight:bold; '&gt;system&lt;/span&gt;&lt;span style='color:#d2cd86; '&gt;(&lt;/span&gt;&lt;span style='color:#00c4c4; '&gt;"cap soa_app:core_service:staging deploy"&lt;/span&gt;&lt;span style='color:#d2cd86; '&gt;)&lt;/span&gt;
   
   Capistrano::CLI&lt;span style='color:#d2cd86; '&gt;.&lt;/span&gt;ui&lt;span style='color:#d2cd86; '&gt;.&lt;/span&gt;say &lt;span style='color:#00c4c4; '&gt;"deploying user_service:staging"&lt;/span&gt;
   &lt;span style='color:#e66170; font-weight:bold; '&gt;system&lt;/span&gt;&lt;span style='color:#d2cd86; '&gt;(&lt;/span&gt;&lt;span style='color:#00c4c4; '&gt;"cap soa_app:user_service:staging deploy"&lt;/span&gt;&lt;span style='color:#d2cd86; '&gt;)&lt;/span&gt;
   
   Capistrano::CLI&lt;span style='color:#d2cd86; '&gt;.&lt;/span&gt;ui&lt;span style='color:#d2cd86; '&gt;.&lt;/span&gt;say &lt;span style='color:#00c4c4; '&gt;"deploying billing_service:staging"&lt;/span&gt;
   &lt;span style='color:#e66170; font-weight:bold; '&gt;system&lt;/span&gt;&lt;span style='color:#d2cd86; '&gt;(&lt;/span&gt;&lt;span style='color:#00c4c4; '&gt;"cap soa_app:billing_service:staging deploy"&lt;/span&gt;&lt;span style='color:#d2cd86; '&gt;)&lt;/span&gt;
 &lt;span style='color:#e66170; font-weight:bold; '&gt;end&lt;/span&gt;
 &lt;span style='color:#d2cd86; '&gt;.&lt;/span&gt;&lt;span style='color:#d2cd86; '&gt;.&lt;/span&gt;&lt;span style='color:#d2cd86; '&gt;.&lt;/span&gt;
&lt;span style='color:#e66170; font-weight:bold; '&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;We’ll need a (dummy) configuration environment for this so create an empty file config/deploy/soa_app.rb.&lt;p&gt;

&lt;p&gt;Now we can deploy to staging by executing&lt;/p&gt;
&lt;pre&gt;$ cap soa_app deploy_all:staging&lt;/pre&gt;

&lt;p&gt;Once you get your deployment application functional, I recommend reading http://jondavidjohn.com/blog/2012/04/cleaning-up-capistrano-deployment-output.&lt;/p&gt;

&lt;div&gt;References&lt;/div&gt;
&lt;div&gt;capistrano&lt;/div&gt;
&lt;div&gt;capistrano-multiconfig&lt;/div&gt;
&lt;div&gt;capistrano-uptodate&lt;/div&gt;
&lt;div&gt;rvm-capistrano&lt;/div&gt;
&lt;div&gt;caphub&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=6v7ThfCZygQ:SbRKcNCp820:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=6v7ThfCZygQ:SbRKcNCp820:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=6v7ThfCZygQ:SbRKcNCp820:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?i=6v7ThfCZygQ:SbRKcNCp820:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=6v7ThfCZygQ:SbRKcNCp820:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=6v7ThfCZygQ:SbRKcNCp820:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=6v7ThfCZygQ:SbRKcNCp820:u0Zhe-nyOHo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=u0Zhe-nyOHo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=6v7ThfCZygQ:SbRKcNCp820:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?i=6v7ThfCZygQ:SbRKcNCp820:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=6v7ThfCZygQ:SbRKcNCp820:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/randomutterings/blog/~4/6v7ThfCZygQ" height="1" width="1"/&gt;</description>
      <pubDate>Tue, 26 Mar 2013 00:58:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:c5084be9-67f3-4e3a-96a4-b8b483a70d86</guid>
      <author>Chris Barnes</author>
      <link>http://feedproxy.google.com/~r/randomutterings/blog/~3/6v7ThfCZygQ/centralized-multi-deployment-approach-with-capistrano</link>
      <category>Deployment</category>
      <category>rails</category>
      <category>soa</category>
      <category>deployment</category>
      <category>capistrano</category>
      <category>multiconfig</category>
      <trackback:ping>http://blog.randomutterings.com/articles/trackback/35</trackback:ping>
    <feedburner:origLink>http://blog.randomutterings.com/articles/2013/03/26/centralized-multi-deployment-approach-with-capistrano</feedburner:origLink></item>
    <item>
      <title>Undo Git Commit</title>
      <description>&lt;p&gt;I just made a commit to a public project and pushed the changes up to github.  Then I realized that I left some confidential information in one of the files.  Searching online lead to a couple of different ways to fix this (git rebase, and git filter-branch), neither of which were working well for me.&lt;/p&gt;

&lt;p&gt;I finally figured out that doing the following would work as long as the confidential information were only included in the last commit.&lt;/p&gt;

&lt;p&gt;First update the file and remove the confidential info.&lt;/p&gt;

&lt;p&gt;git add my-file-with-confidential-info&lt;/p&gt;

&lt;p&gt;git commit --amend
&lt;br&gt;
(this will add what's in your current staging area to the last commit)&lt;/p&gt;

&lt;p&gt;git push origin +master
&lt;br&gt;
(force push your changes to github)&lt;/p&gt;

&lt;p&gt;Hope this helps someone else.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=3V2y9va-Dz0:dG1hvt-q7PY:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=3V2y9va-Dz0:dG1hvt-q7PY:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=3V2y9va-Dz0:dG1hvt-q7PY:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?i=3V2y9va-Dz0:dG1hvt-q7PY:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=3V2y9va-Dz0:dG1hvt-q7PY:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=3V2y9va-Dz0:dG1hvt-q7PY:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=3V2y9va-Dz0:dG1hvt-q7PY:u0Zhe-nyOHo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=u0Zhe-nyOHo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=3V2y9va-Dz0:dG1hvt-q7PY:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?i=3V2y9va-Dz0:dG1hvt-q7PY:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=3V2y9va-Dz0:dG1hvt-q7PY:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/randomutterings/blog/~4/3V2y9va-Dz0" height="1" width="1"/&gt;</description>
      <pubDate>Sun, 18 Apr 2010 12:00:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:5cf4c350-8e45-4b61-8a55-845c6d181b02</guid>
      <author>Chris Barnes</author>
      <link>http://feedproxy.google.com/~r/randomutterings/blog/~3/3V2y9va-Dz0/undo-git-commit</link>
      <category>git</category>
      <category>github</category>
      <trackback:ping>http://blog.randomutterings.com/articles/trackback/34</trackback:ping>
    <feedburner:origLink>http://blog.randomutterings.com/articles/2010/04/18/undo-git-commit</feedburner:origLink></item>
    <item>
      <title>Open Source Wedding</title>
      <description>&lt;p class="credits"&gt;&lt;img src="http://blog.randomutterings.com/images/articles/wedding_500w.png"&gt;&lt;/p&gt;

&lt;p&gt;I'm getting Married this October and so I've created a wedding site for my personal use (&lt;a href="http://www.fairbarneswedding.com"&gt;http://www.fairbarneswedding.com&lt;/a&gt;). I thought, why should I use it once and leave it to rot in source control somewhere? So I'm releasing it under the GNU GPL.&lt;/p&gt;

&lt;p&gt;At the time of this writing the project has news articles, events calendar with rsvp, paypal integrated donation meter, wedding party members, wedding stories, and static pages. If you fork the project and make it better, send me a push request. You can find the source at &lt;a href="http://github.com/randomutterings/wedding"&gt;http://github.com/randomutterings/wedding&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=yE_z5UNqQSM:ZWSo6V3ljPc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=yE_z5UNqQSM:ZWSo6V3ljPc:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=yE_z5UNqQSM:ZWSo6V3ljPc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?i=yE_z5UNqQSM:ZWSo6V3ljPc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=yE_z5UNqQSM:ZWSo6V3ljPc:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=yE_z5UNqQSM:ZWSo6V3ljPc:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=yE_z5UNqQSM:ZWSo6V3ljPc:u0Zhe-nyOHo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=u0Zhe-nyOHo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=yE_z5UNqQSM:ZWSo6V3ljPc:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?i=yE_z5UNqQSM:ZWSo6V3ljPc:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=yE_z5UNqQSM:ZWSo6V3ljPc:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/randomutterings/blog/~4/yE_z5UNqQSM" height="1" width="1"/&gt;</description>
      <pubDate>Tue, 16 Mar 2010 08:37:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:d85aebff-5986-4d9a-b2a0-a54a039f21f4</guid>
      <author>Chris Barnes</author>
      <link>http://feedproxy.google.com/~r/randomutterings/blog/~3/yE_z5UNqQSM/open-source-wedding</link>
      <category>Ruby on Rails</category>
      <category>ruby</category>
      <category>rails</category>
      <category>open</category>
      <category>source</category>
      <category>wedding</category>
      <category>website</category>
      <trackback:ping>http://blog.randomutterings.com/articles/trackback/33</trackback:ping>
    <feedburner:origLink>http://blog.randomutterings.com/articles/2010/03/16/open-source-wedding</feedburner:origLink></item>
    <item>
      <title>Changing images with JQuery and the fade effect</title>
      <description>&lt;p class="credits"&gt;&lt;img style="width:600px;" src="http://blog.randomutterings.com/images/articles/gallery.png"&gt;&lt;br&gt;Photo by &lt;a href="http://www.flickr.com/photos/randomutterings/"&gt;me!&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It took me a bit of digging to figure out how to fade out a picture, change the src, then fade it back in.  I started out trying to use Scriptaculous but I got stuck trying to get the queue setup to wait until the image was faded out to change the src.  I ended up using jQuery which also gave me a bonus, the solution is unabtrusive.&lt;/p&gt;

&lt;p&gt;Here are the application.js and show.html.haml files from my project.&lt;/p&gt;

&lt;script src="http://gist.github.com/64723.js"&gt;&lt;/script&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=w1xYi2xwk4I:X_rmqzJtFuA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=w1xYi2xwk4I:X_rmqzJtFuA:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=w1xYi2xwk4I:X_rmqzJtFuA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?i=w1xYi2xwk4I:X_rmqzJtFuA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=w1xYi2xwk4I:X_rmqzJtFuA:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=w1xYi2xwk4I:X_rmqzJtFuA:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=w1xYi2xwk4I:X_rmqzJtFuA:u0Zhe-nyOHo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=u0Zhe-nyOHo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=w1xYi2xwk4I:X_rmqzJtFuA:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?i=w1xYi2xwk4I:X_rmqzJtFuA:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=w1xYi2xwk4I:X_rmqzJtFuA:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/randomutterings/blog/~4/w1xYi2xwk4I" height="1" width="1"/&gt;</description>
      <pubDate>Sun, 15 Feb 2009 10:14:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:3c3f2d0f-45b6-4208-8135-cb9a144b2694</guid>
      <author>Chris Barnes</author>
      <link>http://feedproxy.google.com/~r/randomutterings/blog/~3/w1xYi2xwk4I/changing-images-with-jquery-and-the-fade-effect</link>
      <category>Ruby on Rails</category>
      <category>Javascript</category>
      <category>ruby</category>
      <category>rails</category>
      <category>Javascript</category>
      <category>JQuery</category>
      <trackback:ping>http://blog.randomutterings.com/articles/trackback/32</trackback:ping>
    <feedburner:origLink>http://blog.randomutterings.com/articles/2009/02/15/changing-images-with-jquery-and-the-fade-effect</feedburner:origLink></item>
    <item>
      <title>Pool-party, Auto-scaling with EC2</title>
      <description>&lt;p class="credits"&gt;&lt;img src="http://blog.randomutterings.com/images/articles/489184472_214de5bfee.jpg"&gt;&lt;br&gt;Photo by &lt;a href="http://www.flickr.com/photos/mancake/489184472/"&gt;hrlndspnks&lt;/a&gt;&lt;/p&gt;

Having a great time at Railsconf08.  Meeting some great people and learning a lot.  I plan to post in more detail about a lot of this after the conference but I wanted to go ahead and mention one of the coolest presentations I've seen so far.&lt;br&gt;&lt;br&gt;

Ari Lerner has created a ruby gem called pool-party.  It auto-scales your ec2 cluster based on criteria you set in the config file like average requests per second.  Set your minimum requests per second and if the average of all the servers on your cluster goes over the maximum, pool-party will launch another instance for you.  It scales down in the same way.  It doesn't care what you're using your cluster for and a its going to support plugins soon so you can add in your own hook like functionality.  Pool-party is using s3fuse to mount an s3 bucket on the instance  at startup.  Specify a bucket in pool-party and it gets mounted at /data on each instance.  This solves the data persistence issue with ec2.  You're not required to use it though, just don't specify a bucket in pool-party and nothing gets mounted.&lt;br&gt;&lt;br&gt;

Ari open-sourced Pool Party as of 2 days ago.  Check it out at poolpartyrb.com.  If you want to contribute, its on github at &lt;a href="http://github.com/auser/pool-party"&gt;http://github.com/auser/pool-party&lt;/a&gt;.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=8ecZZizuZRw:cICgxrPjFGA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=8ecZZizuZRw:cICgxrPjFGA:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=8ecZZizuZRw:cICgxrPjFGA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?i=8ecZZizuZRw:cICgxrPjFGA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=8ecZZizuZRw:cICgxrPjFGA:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=8ecZZizuZRw:cICgxrPjFGA:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=8ecZZizuZRw:cICgxrPjFGA:u0Zhe-nyOHo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=u0Zhe-nyOHo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=8ecZZizuZRw:cICgxrPjFGA:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?i=8ecZZizuZRw:cICgxrPjFGA:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=8ecZZizuZRw:cICgxrPjFGA:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/randomutterings/blog/~4/8ecZZizuZRw" height="1" width="1"/&gt;</description>
      <pubDate>Sat, 31 May 2008 12:03:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:4782b450-7a55-407d-a16a-36a5a449fdb5</guid>
      <author>Chris Barnes</author>
      <link>http://feedproxy.google.com/~r/randomutterings/blog/~3/8ecZZizuZRw/pool-party-auto-scaling-with-ec2</link>
      <category>Infrastructure</category>
      <category>Ruby on Rails</category>
      <category>pool</category>
      <category>party</category>
      <category>ruby</category>
      <category>rails</category>
      <category>infrastructure</category>
      <category>railsconf2008</category>
      <trackback:ping>http://blog.randomutterings.com/articles/trackback/31</trackback:ping>
    <feedburner:origLink>http://blog.randomutterings.com/articles/2008/05/31/pool-party-auto-scaling-with-ec2</feedburner:origLink></item>
    <item>
      <title>Installing git on linux</title>
      <description>&lt;p&gt;Trying to install git from source on our linux server (we're running RHEL4 at work) and I was getting an error running make.&lt;/p&gt;

&lt;pre&gt;
undefined reference to `libiconv'
&lt;/pre&gt;

&lt;p&gt;Running make like this worked.&lt;/p&gt;

&lt;pre&gt;
make install CFLAGS="-liconv"
&lt;/pre&gt;

&lt;p&gt;But after the install was finished, running git barfed at me about loading a shared library libiconv.so.2.&lt;/p&gt;

&lt;p&gt;I had to edit /etc/ld.so.conf and add /usr/local/lib and run ldconfig.&lt;/p&gt;

&lt;p&gt;Credit Mark Turner for the ldconfig tip.  Thanks man.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=wF3n0eaeSqs:91KoyplNUHo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=wF3n0eaeSqs:91KoyplNUHo:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=wF3n0eaeSqs:91KoyplNUHo:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?i=wF3n0eaeSqs:91KoyplNUHo:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=wF3n0eaeSqs:91KoyplNUHo:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=wF3n0eaeSqs:91KoyplNUHo:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=wF3n0eaeSqs:91KoyplNUHo:u0Zhe-nyOHo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=u0Zhe-nyOHo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=wF3n0eaeSqs:91KoyplNUHo:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?i=wF3n0eaeSqs:91KoyplNUHo:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=wF3n0eaeSqs:91KoyplNUHo:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/randomutterings/blog/~4/wF3n0eaeSqs" height="1" width="1"/&gt;</description>
      <pubDate>Thu, 24 Apr 2008 12:32:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:2b5d5fae-9a73-438b-b960-c035f75aa056</guid>
      <author>Chris Barnes</author>
      <link>http://feedproxy.google.com/~r/randomutterings/blog/~3/wF3n0eaeSqs/installing-git-on-linux</link>
      <category>Infrastructure</category>
      <category>git</category>
      <category>scm</category>
      <category>linux</category>
      <trackback:ping>http://blog.randomutterings.com/articles/trackback/29</trackback:ping>
    <feedburner:origLink>http://blog.randomutterings.com/articles/2008/04/24/installing-git-on-linux</feedburner:origLink></item>
    <item>
      <title>Making the jump to full time freelancing</title>
      <description>&lt;p class="credits"&gt;&lt;img src="http://blog.randomutterings.com/images/articles/566425621_2ec5e07914.jpg"&gt;&lt;br&gt;Photo by &lt;a href="http://www.flickr.com/photos/13422316@N00/"&gt;Jack Spellingbacon&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This week its all about changes.  I've moved most of the site over to Radiant, except for the blog.  I've also done some design changes and added a &lt;a href="http://www.randomutterings.com/hire"&gt;hire me&lt;/a&gt; page.  This is in anticipation of May 15th when I'm planning to start full time freelancing.  I've been doing development for 10 years now.  I have experience running my own business and working closely with clients and end users so although its a new season for me, its not something I'm unfamiliar with.&lt;/p&gt;

&lt;p&gt;Something that I am completely new to is teaching children.  I'm planning to begin home schooling my kids in the coming months and I'll be writing about that in the blog as well.  If you're interested in home schooling or freelancing or you just want to follow along to see how things go, &lt;a href="http://feeds.feedburner.com/randomutterings/blog"&gt;subscribe&lt;/a&gt; to the blog.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=ZQHPCA759hk:v-215oh1Crg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=ZQHPCA759hk:v-215oh1Crg:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=ZQHPCA759hk:v-215oh1Crg:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?i=ZQHPCA759hk:v-215oh1Crg:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=ZQHPCA759hk:v-215oh1Crg:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=ZQHPCA759hk:v-215oh1Crg:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=ZQHPCA759hk:v-215oh1Crg:u0Zhe-nyOHo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=u0Zhe-nyOHo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=ZQHPCA759hk:v-215oh1Crg:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?i=ZQHPCA759hk:v-215oh1Crg:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=ZQHPCA759hk:v-215oh1Crg:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/randomutterings/blog/~4/ZQHPCA759hk" height="1" width="1"/&gt;</description>
      <pubDate>Tue, 15 Apr 2008 20:47:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:aa728a88-5e17-4f07-9152-6c38ee70d254</guid>
      <author>Chris Barnes</author>
      <link>http://feedproxy.google.com/~r/randomutterings/blog/~3/ZQHPCA759hk/making-the-jump-to-full-time-freelancing</link>
      <category>Freelancing</category>
      <category>freelancing</category>
      <trackback:ping>http://blog.randomutterings.com/articles/trackback/28</trackback:ping>
    <feedburner:origLink>http://blog.randomutterings.com/articles/2008/04/15/making-the-jump-to-full-time-freelancing</feedburner:origLink></item>
    <item>
      <title>Fixed Length Random numbers in Ruby</title>
      <description>&lt;p&gt;My latest project is almost complete and we're setting up a demo site with lots of fake data already included so I used the faker gem to generate most of it.&lt;/p&gt;

&lt;p&gt;One issue I had that I couldn't do with the faker gem out of the box is get a fixed length random number.  I need this for license numbers, credit card numbers, phone numbers and others.  The faker gem does offer a random phone number but the ones in my project don't support extensions or punctuation so rather than generating the number then using string functions to strip out the stuff I didn't want, I decided to find an easier way.&lt;/p&gt;

&lt;p&gt;I started by Googling for it assuming that someone else had already figured it out and while I'm sure its been done a hundred times before, I couldn't find it anywhere.  So after much thought and digging through the ruby docs, this is what I came up with.&lt;/p&gt;

&lt;blockquote&gt;
&lt;code&gt;
rand(9999999999).to_s.center(10, rand(9).to_s)
&lt;/code&gt;
&lt;/blockquote&gt;

&lt;p&gt;rand(9999999999) will give me a number between 0 and 9999999999.  Convert it to a string and use the center method to make sure its at least 10 digits long and pad the rest with a random number from 0-9.  rand(9)&lt;/p&gt;

&lt;p&gt;If you need a number of say 7 digits in length, just change the first rand to rand(9999999) and change the center method length to 7 so it looks like this.&lt;/p&gt;

&lt;blockquote&gt;
&lt;code&gt;
rand(9999999).to_s.center(7, rand(9).to_s)
&lt;/code&gt;
&lt;/blockquote&gt;

&lt;p&gt;Hope this is helpful to someone.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=08MEzbYPG34:OFyVNSAuFAU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=08MEzbYPG34:OFyVNSAuFAU:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=08MEzbYPG34:OFyVNSAuFAU:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?i=08MEzbYPG34:OFyVNSAuFAU:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=08MEzbYPG34:OFyVNSAuFAU:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=08MEzbYPG34:OFyVNSAuFAU:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=08MEzbYPG34:OFyVNSAuFAU:u0Zhe-nyOHo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=u0Zhe-nyOHo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=08MEzbYPG34:OFyVNSAuFAU:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?i=08MEzbYPG34:OFyVNSAuFAU:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=08MEzbYPG34:OFyVNSAuFAU:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/randomutterings/blog/~4/08MEzbYPG34" height="1" width="1"/&gt;</description>
      <pubDate>Wed, 09 Jan 2008 11:20:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:3d11eeca-de64-42c7-86ea-9f74999c2057</guid>
      <author>Chris Barnes</author>
      <link>http://feedproxy.google.com/~r/randomutterings/blog/~3/08MEzbYPG34/fixed-length-random-numbers-in-ruby</link>
      <category>Ruby on Rails</category>
      <category>ruby</category>
      <category>random</category>
      <category>numbers</category>
      <category>faker</category>
      <category>gem</category>
      <trackback:ping>http://blog.randomutterings.com/articles/trackback/26</trackback:ping>
    <feedburner:origLink>http://blog.randomutterings.com/articles/2008/01/09/fixed-length-random-numbers-in-ruby</feedburner:origLink></item>
    <item>
      <title>Subversion script for Rails developers</title>
      <description>&lt;p&gt;I read somewhere that good developers use version control.  There's a good article on &lt;a href="http://wiki.rubyonrails.org/rails/pages/HowtoUseRailsWithSubversion"&gt;HowtoUseRailsWithSubversion&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So why should I repeat those steps for every new project I work on.&lt;/p&gt;

&lt;p&gt;There is another &lt;a href="http://www.railsonwave.com/railsonwave/2006/12/19/smart-subversion-script-for-rails-projects"&gt;article&lt;/a&gt; which attempted to tackle this problem.  However, you still have to do the initial steps and then copy this script into your project directory and execute it.&lt;/p&gt;

&lt;p&gt;The following script takes it a bit farther.  You call it like this.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;rails-svn app_dir repository username
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So if I wanted to create a new rails project called toejam, I would execute:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;rails-svn toejam svn://randomutterings.com/projects/toejam/trunk chris
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here's what happens under the hood.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;After checking to make sure the directory doesn't already exist, your rails app is created with the standard rails command.  (If the directory already exists, you will be asked if you want to continue.  Choosing yes will allow the script to continue but if this script has been run on the same app twice, all of the svn commits will be duplicated.)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Your new app is imported to the subversion repository specified.  Authentication is done with the username provided.  You may be prompted for a password from your repository.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The original app directory is deleted and a working copy is checked out from the repository into that directory.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;All the default rails log files are removed and subversion is instructed to ignore those files.  (Log files can get large and we definitely don't need them in version control.)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The database.yml is moved to database.example to serve as a template for anyone who checks out the code and any newly created database.yml files are ignored by subversion.  (Doing this will help if you have multiple developers working on the same project in different environments.  It also prevents you from overwriting the database.yml file on the production server, oops!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Subversion is told to ignore everything in the tmp folder, the .htaccess files, and the dispatch.fcgi file.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Without further ado, here's the script.  Just copy it and save it somewhere in your path.  /usr/bin is a good choice.  Don't forget to chmod 755 so you can execute it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;pre&gt;
    #!/bin/bash

    if [ "$#" != "3" ]; then
      echo "Usage: rails-svn app_dir repository username"
      exit 1
    fi

    APPDIR=./$1
    SVN_TRUNK=$2
    SVN_USER=$3

    function check_if_exist () {
      if [[ -e $1 ]]; then
        echo ""
        echo "$1 already exists, overwrite? y or n"
        echo ""
        read OVERWRITE
        case "$OVERWRITE" in
        y)
          echo "Overwriting..."
          ;;
        *)
          echo "Action canceled"
          exit 1
          ;;
        esac
      fi
    }

    check_if_exist ${APPDIR}
    rails $APPDIR
    svn import $APPDIR $SVN_TRUNK -m "Import" --username $SVN_USER
    sudo rm -r $APPDIR
    svn checkout $SVN_TRUNK $APPDIR
    cd $APPDIR

    svn remove log/*
    svn commit -m "removing log files" 
    svn propset svn:ignore "*.log" log/
    svn update log/
    svn commit -m "Ignoring all files in /log/ ending in .log"
    svn move config/database.yml config/database.example
    svn commit -m "Moving database.yml to database.example to provide a template for anyone who checks out the code"
    svn propset svn:ignore "database.yml" config/
    svn update config/
    svn commit -m "Ignoring database.yml"
    svn remove tmp/*
    svn propset svn:ignore "*" tmp/
    svn update tmp/
    svn commit -m "ignore tmp/ content from now" 
    svn propset svn:ignore ".htaccess" public/
    svn update public/
    svn commit -m "Ignoring .htaccess"
    svn propset svn:ignore "dispatch.fcgi" public/
    svn update public/
    svn commit -m "Ignoring dispatch.fcgi"
&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;I'm interested in converting this into a gem and possibly rewriting it in ruby.  If anyone has the skills and wants to contribute, leave a comment or &lt;a href="mailto:randomutterings@gmail.com"&gt;email me&lt;/a&gt;.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=Olt5RO7xeKI:H9GDDBws67g:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=Olt5RO7xeKI:H9GDDBws67g:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=Olt5RO7xeKI:H9GDDBws67g:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?i=Olt5RO7xeKI:H9GDDBws67g:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=Olt5RO7xeKI:H9GDDBws67g:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=Olt5RO7xeKI:H9GDDBws67g:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=Olt5RO7xeKI:H9GDDBws67g:u0Zhe-nyOHo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=u0Zhe-nyOHo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=Olt5RO7xeKI:H9GDDBws67g:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?i=Olt5RO7xeKI:H9GDDBws67g:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=Olt5RO7xeKI:H9GDDBws67g:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/randomutterings/blog/~4/Olt5RO7xeKI" height="1" width="1"/&gt;</description>
      <pubDate>Wed, 19 Sep 2007 15:15:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:39260e1f-ef69-495a-93fe-7ae6cfb13748</guid>
      <author>Chris Barnes</author>
      <link>http://feedproxy.google.com/~r/randomutterings/blog/~3/Olt5RO7xeKI/subversion-script-for-rails-developers</link>
      <category>Ruby on Rails</category>
      <category>Subversion</category>
      <category>ruby</category>
      <category>rails</category>
      <category>Scripts</category>
      <category>bash</category>
      <trackback:ping>http://blog.randomutterings.com/articles/trackback/25</trackback:ping>
    <feedburner:origLink>http://blog.randomutterings.com/articles/2007/09/19/subversion-script-for-rails-developers</feedburner:origLink></item>
    <item>
      <title>Rapt error during peepcodes test first development tutorial</title>
      <description>&lt;p&gt;OK, let me start off by saying, I love the tutorials from peepcode, you guys are doing a great job so keep doing it.&lt;/p&gt;

&lt;p&gt;Alas, I got stuck while watching the &lt;a href="http://peepcode.com/products/test-first-development"&gt;Test-first-development&lt;/a&gt; tutorial.  They were using &lt;a href="http://rapt.rubyforge.org/"&gt;Rapt&lt;/a&gt; as an alternative to script/plugin and when I tried to run it I kept getting an error.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Error: RaPT currently does not work outside of a Rails application directory.  Please change to the top level of a Rails application and try again.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This error is misleading but at least it was obviously misleading, after all I know I'm in my Rails application directory.&lt;/p&gt;

&lt;p&gt;After some googling, I found a post describing a work around for the problem, but it basically gave instructions on installing the plugin with script/plugin.  But the guys at peepcode had a reason for using rapt over script/plugin (its faster).  So I Google some more.  I finally find a &lt;a href="http://rubyforge.org/tracker/index.php?func=detail&amp;aid=6611&amp;group_id=1889&amp;atid=7384"&gt;bug &lt;/a&gt; on the Rapt &lt;a href="http://rubyforge.org/projects/rapt/"&gt;Trac&lt;/a&gt; posted in 2006 that explains that the user must first add repositories by executing the following.&lt;/p&gt;

&lt;pre&gt;
&lt;p&gt;rapt discover&lt;/p&gt;
&lt;/pre&gt;

&lt;p&gt;If anyone knows how to have it default to yes without prompting you for every repository, please post a comment.&lt;/p&gt;

&lt;p&gt;Alternatively, you can add only the repositories you want to use by executing the following.&lt;/p&gt;

&lt;pre&gt;
&lt;p&gt;rapt source http://path-to-repository&lt;/p&gt;
&lt;/pre&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=QEfAgsAGdRo:cCLCwxhDvdo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=QEfAgsAGdRo:cCLCwxhDvdo:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=QEfAgsAGdRo:cCLCwxhDvdo:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?i=QEfAgsAGdRo:cCLCwxhDvdo:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=QEfAgsAGdRo:cCLCwxhDvdo:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=QEfAgsAGdRo:cCLCwxhDvdo:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=QEfAgsAGdRo:cCLCwxhDvdo:u0Zhe-nyOHo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=u0Zhe-nyOHo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=QEfAgsAGdRo:cCLCwxhDvdo:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?i=QEfAgsAGdRo:cCLCwxhDvdo:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/randomutterings/blog?a=QEfAgsAGdRo:cCLCwxhDvdo:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/randomutterings/blog?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/randomutterings/blog/~4/QEfAgsAGdRo" height="1" width="1"/&gt;</description>
      <pubDate>Thu, 13 Sep 2007 12:47:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:a5ba1b07-1d85-4136-9454-4820007eb561</guid>
      <author>Chris Barnes</author>
      <link>http://feedproxy.google.com/~r/randomutterings/blog/~3/QEfAgsAGdRo/rapt-error-during-peepcodes-test-first-development-tutorial</link>
      <category>Ruby on Rails</category>
      <category>ruby</category>
      <category>rails</category>
      <category>rapt</category>
      <category>plugins</category>
      <category>peepcode</category>
      <category>tutorial</category>
      <category>screencast</category>
      <trackback:ping>http://blog.randomutterings.com/articles/trackback/22</trackback:ping>
    <feedburner:origLink>http://blog.randomutterings.com/articles/2007/09/13/rapt-error-during-peepcodes-test-first-development-tutorial</feedburner:origLink></item>
  </channel>
</rss>
