<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
 
 <title>The Solutious Blog</title>
 <link href="http://solutious.com/blog/atom.rss" rel="self"/>
 <link href="http://solutious.com/blog/"/>
 <updated>2023-04-14T04:06:36+00:00</updated>
 <id>http://solutious.com/blog/</id>
 <author>
   <name>Solutious Inc.</name>
   <email>info@solutious.com</email>
 </author>
 
 
 <entry>
   <title>So I made over 52,000 mistakes today</title>
   <link href="http://solutious.com/blog/2013/02/06/so-i-made-52000-mistakes-today/"/>
   <updated>2013-02-06T00:00:00+00:00</updated>
   <id>http://solutious.com/blog/2013/02/06/so-i-made-52000-mistakes-today</id>
   <content type="html">&lt;p&gt;Earlier today I &lt;a href=&quot;/blog/2013/02/06/net-ssh-gem-code-signed/&quot;&gt;updated&lt;/a&gt; the net-ssh family of Ruby gems and I broke one of the rules of &lt;a href=&quot;http://semver.org/&quot;&gt;semantic versioning&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Specifically, rule #8:&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;8. Minor version Y (x.Y.z | x &amp;gt; 0) MUST be incremented if new,
backwards compatible functionality is introduced to the public API.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I broke &lt;a href=&quot;http://tickets.opscode.com/browse/CHEF-3835&quot;&gt;Chef&lt;/a&gt;. I broke &lt;a href=&quot;https://github.com/mitchellh/vagrant/issues/1355&quot;&gt;Vagrant&lt;/a&gt;. net-ssh is pretty far upstream so in just a couple hours there were over 52,000 installs of the offending gems, &lt;em&gt;much to the chagrin of sysadmins and devops folks everywhere.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: If you have any of the following gems installed on your system, you should remove them: net-ssh-gateway-1.1.1, net-ssh-gateway-1.1.2, net-ssh-multi-1.1.1, net-ssh-multi-1.1.2, net-scp-1.0.5, and net-scp-1.0.6. See my &lt;a href=&quot;/blog/2013/02/06/net-ssh-gem-code-signed/&quot;&gt;previous post&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;the-err-of-my-ways&quot;&gt;The err of my ways&lt;/h2&gt;

&lt;p&gt;I released three gems with the PATCH incremented instead of the MINOR version number. This makes a huge difference downstream because of the “&lt;a href=&quot;http://twiddlewakka.com/&quot;&gt;twiddle-wakka&lt;/a&gt;”:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# Meanwhile, in chef.gemspec
s.add_dependency &quot;net-ssh&quot;, &quot;~&amp;gt; 2.2.2&quot;
s.add_dependency &quot;net-ssh-multi&quot;, &quot;~&amp;gt; 1.1.0&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~&amp;gt;&lt;/code&gt; will &lt;a href=&quot;http://robots.thoughtbot.com/post/2508037841/rubys-pessimistic-operator&quot;&gt;fuzzily match&lt;/a&gt; any gems less than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1.2&lt;/code&gt; but greater than or equal to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1.1.0&lt;/code&gt;. This feature strikes a balance between &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;&amp;gt;= 1.1.0&quot;&lt;/code&gt; (which is too loose) and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;= 1.1.0&quot;&lt;/code&gt; (which is too strict). The problem is that net-ssh-multi-1.1.2 &lt;em&gt;changed the net-ssh dependency to 2.6.5&lt;/em&gt; which made Chef uninstallable due to the conflict between chef.gemspec and net-ssh-multi.gemspec (2.2.x vs 2.6.5). Feels bad man.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So if I ruined your day, &lt;a href=&quot;https://onetimesecret.com/feedback&quot;&gt;send me&lt;/a&gt; your email, Twitter, Skype, or phone number and I will reply with a personal apology.&lt;/strong&gt;&lt;/p&gt;

&lt;p style=&quot;color: #999; font-size: 80%&quot;&gt;(Offer expires Feb 12th at 07:59 UTC).&lt;/p&gt;

&lt;h2 id=&quot;on-a-more-positive-note&quot;&gt;On a more positive note&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;A big thank you to everyone who emailed, tweeted, and opened issues to help get this resolved quickly.&lt;/strong&gt; Although regrettable, this is the only significant issue with net-ssh and friends in the &lt;a href=&quot;http://solutious.com/blog/2009/06/19/net-ssh-repository/&quot;&gt;4 years&lt;/a&gt; (and &lt;a href=&quot;https://rubygems.org/profiles/delano&quot;&gt;18M downloads&lt;/a&gt;) that I’ve been maintaining them. I feel pretty good about that.&lt;/p&gt;

&lt;p&gt;Incidentally, I updated the &lt;a href=&quot;https://github.com/net-ssh/net-ssh/blob/v2.6.5/THANKS.txt&quot;&gt;THANKS.txt&lt;/a&gt; that’s part of every net-ssh release today too. I added the names of all the people who contributed code since I’ve been maintaining it. Here they are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;GOTOU Yuuzou&lt;/li&gt;
  &lt;li&gt;Guillaume Marçais&lt;/li&gt;
  &lt;li&gt;Daniel Berger&lt;/li&gt;
  &lt;li&gt;Chris Andrews&lt;/li&gt;
  &lt;li&gt;Lee Jensen&lt;/li&gt;
  &lt;li&gt;Hiroshi Nakamura&lt;/li&gt;
  &lt;li&gt;Andreas Wolff&lt;/li&gt;
  &lt;li&gt;mhuffnagle&lt;/li&gt;
  &lt;li&gt;ohrite&lt;/li&gt;
  &lt;li&gt;iltempo&lt;/li&gt;
  &lt;li&gt;nagachika&lt;/li&gt;
  &lt;li&gt;Nobuhiro IMAI&lt;/li&gt;
  &lt;li&gt;arturaz&lt;/li&gt;
  &lt;li&gt;dubspeed&lt;/li&gt;
  &lt;li&gt;Andy Brody&lt;/li&gt;
  &lt;li&gt;Marco Sandrini&lt;/li&gt;
  &lt;li&gt;Ryosuke Yamazaki&lt;/li&gt;
  &lt;li&gt;muffl0n&lt;/li&gt;
  &lt;li&gt;pcn&lt;/li&gt;
  &lt;li&gt;musybite&lt;/li&gt;
  &lt;li&gt;Mark Imbriaco&lt;/li&gt;
  &lt;li&gt;Joel Watson&lt;/li&gt;
  &lt;li&gt;Woon Jung&lt;/li&gt;
  &lt;li&gt;Edmund Haselwanter&lt;/li&gt;
  &lt;li&gt;robbebob&lt;/li&gt;
  &lt;li&gt;Daniel Pittman&lt;/li&gt;
  &lt;li&gt;Markus Roberts&lt;/li&gt;
  &lt;li&gt;Gavin Brock&lt;/li&gt;
  &lt;li&gt;Rich Lane&lt;/li&gt;
  &lt;li&gt;Lee Marlow&lt;/li&gt;
  &lt;li&gt;xbaldauf&lt;/li&gt;
  &lt;li&gt;Delano Mandelbaum&lt;/li&gt;
  &lt;li&gt;Miklós Fazekas&lt;/li&gt;
  &lt;li&gt;Andy Lo-A-Foe&lt;/li&gt;
  &lt;li&gt;Jason Weathered&lt;/li&gt;
  &lt;li&gt;Hans de Graaff&lt;/li&gt;
  &lt;li&gt;Travis Reeder&lt;/li&gt;
  &lt;li&gt;Akinori MUSHA&lt;/li&gt;
  &lt;li&gt;Alex Peuchert&lt;/li&gt;
  &lt;li&gt;Daniel Azuma&lt;/li&gt;
  &lt;li&gt;Will Bryant&lt;/li&gt;
  &lt;li&gt;Gerald Talton&lt;/li&gt;
  &lt;li&gt;ckoehler&lt;/li&gt;
  &lt;li&gt;Karl Varga&lt;/li&gt;
  &lt;li&gt;Denis Bernard&lt;/li&gt;
  &lt;li&gt;Steven Hazel&lt;/li&gt;
  &lt;li&gt;Alex Holems&lt;/li&gt;
  &lt;li&gt;Andrew Babkin&lt;/li&gt;
  &lt;li&gt;Bob Cotton&lt;/li&gt;
  &lt;li&gt;Yanko Ivanov&lt;/li&gt;
  &lt;li&gt;Angel N. Sciortino&lt;/li&gt;
  &lt;li&gt;arilerner@mac.com&lt;/li&gt;
  &lt;li&gt;David Dollar&lt;/li&gt;
  &lt;li&gt;Timo Gatsonides&lt;/li&gt;
  &lt;li&gt;Matthew Todd&lt;/li&gt;
  &lt;li&gt;Brian Candler&lt;/li&gt;
  &lt;li&gt;Francis Sullivan&lt;/li&gt;
  &lt;li&gt;James Rosen&lt;/li&gt;
  &lt;li&gt;Mike Timm&lt;/li&gt;
  &lt;li&gt;guns&lt;/li&gt;
  &lt;li&gt;devrandom&lt;/li&gt;
  &lt;li&gt;kachick&lt;/li&gt;
  &lt;li&gt;Pablo Merino&lt;/li&gt;
  &lt;li&gt;thedarkone&lt;/li&gt;
  &lt;li&gt;czarneckid&lt;/li&gt;
  &lt;li&gt;jbarnette&lt;/li&gt;
  &lt;li&gt;watsonian&lt;/li&gt;
  &lt;li&gt;Grant Hutchins&lt;/li&gt;
  &lt;li&gt;Michael Schubert&lt;/li&gt;
  &lt;li&gt;mtrudel&lt;/li&gt;
  &lt;li&gt;and of course, &lt;a href=&quot;https://twitter.com/jamis&quot;&gt;Jamis Buck&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I know I’m not the only one who appreciates your time and effort. Thank you for making net-ssh better!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>All future Net-SSH gem releases will now be signed (as of 2.6.5)</title>
   <link href="http://solutious.com/blog/2013/02/06/net-ssh-gem-code-signed/"/>
   <updated>2013-02-06T00:00:00+00:00</updated>
   <id>http://solutious.com/blog/2013/02/06/net-ssh-gem-code-signed</id>
   <content type="html">&lt;p&gt;&lt;em&gt;**Updated (2013-02-06@13:00PST): Doh. Some previously updated gems were broken. See below. **&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In response to the &lt;a href=&quot;/blog/assets/2013/RubyGems13013IncidentStatus.html&quot;&gt;recent vulnerabilities&lt;/a&gt; with rubygems.org, I spent the morning signing and re-releasing the &lt;a href=&quot;https://github.com/net-ssh&quot;&gt;Net-SSH family&lt;/a&gt; of ruby gems. The discussion on &lt;a href=&quot;http://guides.rubygems.org/publishing/#gem-security&quot;&gt;how to properly handle code signing&lt;/a&gt; is still ongoing so this could be just an interrim measure; however, the severity of the problem makes it necessary to have a solution in place now.&lt;/p&gt;

&lt;h2 id=&quot;current-signed-releases&quot;&gt;Current Signed Releases&lt;/h2&gt;

&lt;p&gt;As of today, all net-ssh releases will be &lt;a href=&quot;http://docs.rubygems.org/read/chapter/21&quot;&gt;signed&lt;/a&gt; and verifiable with the public certificate at the end of this post.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;net-ssh 2.6.5+&lt;/strong&gt; (&lt;a href=&quot;https://rubygems.org/gems/net-ssh/versions/2.6.5&quot;&gt;rubygems&lt;/a&gt;, &lt;a href=&quot;https://github.com/net-ssh/net-ssh/tree/v2.6.5&quot;&gt;github&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;net-scp 1.1.0+&lt;/strong&gt; (&lt;a href=&quot;https://rubygems.org/gems/net-scp/versions/1.1.0&quot;&gt;rubygems&lt;/a&gt;, &lt;a href=&quot;https://github.com/net-ssh/net-scp/tree/v1.1.0&quot;&gt;github&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;net-sftp 2.2.0&lt;/strong&gt; (&lt;a href=&quot;https://rubygems.org/gems/net-sftp/versions/2.2.0&quot;&gt;rubygems&lt;/a&gt;, &lt;a href=&quot;https://github.com/net-ssh/net-sftp/tree/v2.2.0&quot;&gt;github&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;net-ssh-gateway 1.2.0&lt;/strong&gt; (&lt;a href=&quot;https://rubygems.org/gems/net-ssh-gateway/versions/1.2.0&quot;&gt;rubygems&lt;/a&gt;, &lt;a href=&quot;https://github.com/net-ssh/net-ssh-gateway/tree/v1.2.0&quot;&gt;github&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;net-ssh-multi 1.2.0&lt;/strong&gt; (&lt;a href=&quot;https://rubygems.org/gems/net-ssh-multi/versions/1.2.0&quot;&gt;rubygems&lt;/a&gt;, &lt;a href=&quot;https://github.com/net-ssh/net-ssh-multi/tree/v1.2.0&quot;&gt;github&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;installation&quot;&gt;Installation&lt;/h2&gt;

&lt;p&gt;You can still &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gem install net-ssh&lt;/code&gt; like you do already but if you want to verify the gem is authentic, you will now be able to run:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ gem install net-ssh -P HighSecurity
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To do this, you need to add the public certificate to local trust gem certs (otherwise you’ll see an error like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;Couldn't verify data signature&quot;&lt;/code&gt;):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ curl -O https://raw.github.com/net-ssh/net-ssh/master/gem-public_cert.pem
$ gem cert --add gem-public_cert.pem
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;broken-versions&quot;&gt;Broken versions&lt;/h2&gt;

&lt;p&gt;The following gems were broken:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;net-ssh-gateway-1.1.1&lt;/li&gt;
  &lt;li&gt;net-ssh-gateway-1.1.2&lt;/li&gt;
  &lt;li&gt;net-ssh-multi-1.1.1&lt;/li&gt;
  &lt;li&gt;net-ssh-multi-1.1.2&lt;/li&gt;
  &lt;li&gt;net-scp-1.0.5&lt;/li&gt;
  &lt;li&gt;net-scp-1.0.6&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They’ve been yanked from rubygems.org but if already have them on your system, you will need to remove them manually.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ gem uninstall -v 1.1.1 net-ssh-multi
$ gem uninstall -v 1.1.2 net-ssh-multi
$ gem uninstall -v 1.1.1 net-ssh-gateway
$ gem uninstall -v 1.1.2 net-ssh-gateway
$ gem uninstall -v 1.0.5 net-scp
$ gem uninstall -v 1.0.6 net-scp
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you have any trouble let me know at net-ssh@solutious.com.&lt;/p&gt;

&lt;h2 id=&quot;public-certificate&quot;&gt;Public certificate&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;
-----BEGIN CERTIFICATE-----
MIIDNjCCAh6gAwIBAgIBADANBgkqhkiG9w0BAQUFADBBMQ8wDQYDVQQDDAZkZWxh
bm8xGTAXBgoJkiaJk/IsZAEZFglzb2x1dGlvdXMxEzARBgoJkiaJk/IsZAEZFgNj
b20wHhcNMTMwMjA2MTE1NzQ1WhcNMTQwMjA2MTE1NzQ1WjBBMQ8wDQYDVQQDDAZk
ZWxhbm8xGTAXBgoJkiaJk/IsZAEZFglzb2x1dGlvdXMxEzARBgoJkiaJk/IsZAEZ
FgNjb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDg1hMtl0XsMuUK
AKTgYWv3gjj7vuEsE2EjT+vyBg8/LpqVVwZziiaebJT9IZiQ+sCFqbiakj0b53pI
hg1yOaBEmH6/W0L7rwzqaRV9sW1eJs9JxFYQCnd67zUnzj8nnRlOjG+hhIG+Vsij
npsGbt28pefuNZJjO5q2clAlfSniIIHfIsU7/StEYu6FUGOjnwryZ0r5yJlr9RrE
Gs+q0DW8QnZ9UpAfuDFQZuIqeKQFFLE7nMmCGaA+0BN1nLl3fVHNbLHq7Avk8+Z+
ZuuvkdscbHlO/l+3xCNQ5nUnHwq0ADAbMLOlmiYYzqXoWLjmeI6me/clktJCfN2R
oZG3UQvvAgMBAAGjOTA3MAkGA1UdEwQCMAAwHQYDVR0OBBYEFMSJOEtHzE4l0azv
M0JK0kKNToK1MAsGA1UdDwQEAwIEsDANBgkqhkiG9w0BAQUFAAOCAQEAtOdE73qx
OH2ydi9oT2hS5f9G0y1Z70Tlwh+VGExyfxzVE9XwC+iPpJxNraiHYgF/9/oky7ZZ
R9q0/tJneuhAenZdiQkX7oi4O3v9wRS6YHoWBxMPFKVRLNTzvVJsbmfpCAlp5/5g
ps4wQFy5mibElGVlOobf/ghqZ25HS9J6kd0/C/ry0AUtTogsL7TxGwT4kbCx63ub
3vywEEhsJUzfd97GCABmtQfRTldX/j7F1z/5wd8p+hfdox1iibds9ZtfaZA3KzKn
kchWN9B6zg9r1XMQ8BM2Jz0XoPanPe354+lWwjpkRKbFow/ZbQHcCLCq24+N6b6g
dgKfNDzwiDpqCA==
-----END CERTIFICATE-----
&lt;/code&gt;&lt;/pre&gt;
</content>
 </entry>
 
 <entry>
   <title>How RethinkDB Says Thanks</title>
   <link href="http://solutious.com/blog/2012/12/26/how-rethinkdb-says-thanks/"/>
   <updated>2012-12-26T00:00:00+00:00</updated>
   <id>http://solutious.com/blog/2012/12/26/how-rethinkdb-says-thanks</id>
   <content type="html">&lt;p&gt;I posted a couple weeks ago about &lt;a href=&quot;/blog/2012/11/12/installing-rethinkdb-ubuntu/&quot;&gt;my experience installing RethinkDB&lt;/a&gt;. Today I got this in the mail:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/2012/rethink-thankyou.jpg&quot; alt=&quot;Thank you RethinkDB&quot; title=&quot;Who doesn't love getting mail?&quot; /&gt;&lt;/p&gt;

&lt;p&gt;That’s a moleskin and a usb key (with a metal case). The handwritten note is fine touch too.&lt;/p&gt;

&lt;p&gt;Thank you &lt;a href=&quot;https://twitter.com/al3xandru&quot;&gt;@al3xandru&lt;/a&gt; and &lt;a href=&quot;http://www.rethinkdb.com/&quot;&gt;RethinkDB&lt;/a&gt;.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Installing RethinkDB on Ubuntu</title>
   <link href="http://solutious.com/blog/2012/11/12/installing-rethinkdb-ubuntu/"/>
   <updated>2012-11-12T00:00:00+00:00</updated>
   <id>http://solutious.com/blog/2012/11/12/installing-rethinkdb-ubuntu</id>
   <content type="html">&lt;p&gt;&lt;strong&gt;Update: The &lt;a href=&quot;http://www.rethinkdb.com/docs/install/&quot;&gt;installation docs&lt;/a&gt; for Ubuntu have been updated to make the requirements more clear.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.rethinkdb.com/&quot;&gt;RethinkDB&lt;/a&gt; has been getting some more attention in the past few days, starting with &lt;a href=&quot;http://news.ycombinator.com/item?id=4763879&quot;&gt;a Hacker News post last Friday&lt;/a&gt;. The project (and company) was founded in 2009, &lt;a href=&quot;http://techcrunch.com/2011/06/06/rethinkdb-expands-beyond-ssds-launches-its-speedy-database-to-the-public/&quot;&gt;launched the 1.0 release&lt;/a&gt; last year, and although there’s still some work to do in terms of stability and portability, it looks promising.&lt;/p&gt;

&lt;p&gt;In their words:&lt;/p&gt;

&lt;blockquote&gt;&lt;i&gt;RethinkDB is built to store JSON documents, and scale to multiple machines with very little effort. It has a pleasant query language that supports really useful queries like table joins and group by, and is easy to setup and learn.&lt;/i&gt;&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/2012/rethink-admin-freshinstall-s.png&quot; alt=&quot;The built-in RethinkDB admin interface&quot; title=&quot;The built-in admin Interface&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;installation-steps-for-ubuntu&quot;&gt;Installation Steps for Ubuntu&lt;/h2&gt;

&lt;p&gt;I only just got it running after much trial and error so I documented the experience to help others in the same boat. The team is working full steam on &lt;a href=&quot;https://github.com/rethinkdb/rethinkdb/issues&quot;&gt;resolving issues&lt;/a&gt; as they arise so my intent here is one of observation rather than to criticize. Here’s what I’ve gathered so far.&lt;/p&gt;

&lt;h4 id=&quot;requirementslimitations&quot;&gt;Requirements/Limitations&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;Only runs on x86_64 Linux&lt;/li&gt;
  &lt;li&gt;Depends on &lt;a href=&quot;https://github.com/rethinkdb/rethinkdb/issues/6#issuecomment-10263097&quot;&gt;kernel 2.6.37&lt;/a&gt; or greater&lt;/li&gt;
  &lt;li&gt;No RPM (&lt;a href=&quot;https://twitter.com/rethinkdb/status/267785958278176769&quot;&gt;soon&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;
    &lt;strike&gt;Possible issue with ext4 with journaling and/or encrypted partitions&lt;/strike&gt;
    &lt;p&gt;(update from Slava below)&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;strike&gt;Some compilation issues on Debian/CentOS&lt;/strike&gt;
    &lt;p&gt;(working on a Debian post now)&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Update (Nov 12 @ 16:50 PST): Success with ext2 and ext3/ext4 with journaling enabled.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update (Nov 13): Comment from Slava (below):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;&lt;em&gt;We’ll be providing binaries for most platforms and even old kernels, though it will take a bit of time to work out. The portability team here is working around the clock to make it happen.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;&lt;em&gt;Rethink doesn’t work on encrypted file systems because they don’t support direct io. It makes sense in production, but it’d be nice to have a backup mode for trying in dev. See &lt;a href=&quot;https://github.com/rethinkdb/rethinkdb/issues/47&quot;&gt;issue #47&lt;/a&gt;.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So make sure you’re running the 64-bit of version Ubuntu with a non-encrypted ext2, ext3 or ext4 partition and that the kernel version is 2.6.37 or greater. Then:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo apt-get install software-properties-common  # installs add-apt-repository
$ sudo add-apt-repository ppa:rethinkdb/ppa
$ sudo apt-get update
$ sudo apt-get install rethinkdb
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Things are changing almost hourly so be sure to check their &lt;a href=&quot;http://www.rethinkdb.com/community/&quot;&gt;community page&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/rethinkdb&quot;&gt;follow RethinkDB on Twitter&lt;/a&gt; for the latest info.&lt;/p&gt;

&lt;h4 id=&quot;checking-whether-journaling-is-enabled&quot;&gt;Checking whether journaling is enabled&lt;/h4&gt;

&lt;p&gt;Look for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;has_journal&lt;/code&gt; option in the following output:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo debugfs -R features /dev/sda1
debugfs 1.42.5 (29-Jul-2012)
Filesystem features: filetype sparse_super
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You may need to change &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dev/sda1&lt;/code&gt; for your disk device which you can get from the output of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mount&lt;/code&gt;.&lt;/p&gt;

&lt;h4 id=&quot;checking-the-kernel-version&quot;&gt;Checking the kernel version&lt;/h4&gt;

&lt;p&gt;The kernel version is displayed immediately to the right of the hostname:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ uname -a
Linux bs-dev-01 3.5.0-17-generic #28-Ubuntu SMP Tue Oct 9 19:31:23 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

</content>
 </entry>
 
 <entry>
   <title>Some cool uses of Git-like hashes in Ruby (with Gibbler)</title>
   <link href="http://solutious.com/blog/2011/03/11/cool-uses-for-git-like-hashes-with-gibbler/"/>
   <updated>2011-03-11T00:00:00+00:00</updated>
   <id>http://solutious.com/blog/2011/03/11/cool-uses-for-git-like-hashes-with-gibbler</id>
   <content type="html">&lt;p&gt;Cryptographic hashes are pretty cool. They’re often used as checksums for large files because they’re fast, consistent, and well, secure. A lot of opensource software packages are distributed with the MD5 or SHA1 hash so that you can verify that all the bits are in the correct place (i.e. that the file you downloaded is identical to the one being served). If you’ve used Mercurial or Git, you’ve seen them used there too to track commits, objects, and trees.&lt;/p&gt;

&lt;p&gt;Hashes can also be a useful tool in your code and I wrote &lt;a href=&quot;https://github.com/delano/gibbler&quot;&gt;Gibbler&lt;/a&gt; to make it easy to do that. Why not use Ruby’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hash&lt;/code&gt; method? Because the return values are inconsistent between runs.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;t1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;now&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;t2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;clone&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;t1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;hash&lt;/span&gt;                       &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; -2827223250544534006&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;t2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;hash&lt;/span&gt;                       &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; -2827223250544534006 (the same!)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;t1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;object_id&lt;/span&gt;                  &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; 2170505820&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;t2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;object_id&lt;/span&gt;                  &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; 2170481360&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Later on, with another instance of Ruby&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;t1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;now&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;t1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;hash&lt;/span&gt;                       &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; 2265941047042223117 (different!)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;t1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;object_id&lt;/span&gt;                  &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; 2168957700&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;But as it turns out, you can do some neat stuff when you can rely on the values between runs, using different versions and implementations of Ruby. I’m going to point a few, but first a quick introduction.&lt;/p&gt;

&lt;h3 id=&quot;a-quick-intro-to-gibbler&quot;&gt;A quick intro to Gibbler&lt;/h3&gt;

&lt;p&gt;When you require gibbler, you get a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gibbler&lt;/code&gt; method installed into most rudimentary Objects like &lt;a href=&quot;https://github.com/delano/gibbler/blob/v0.8.9/lib/gibbler.rb#L365&quot;&gt;String&lt;/a&gt;, &lt;a href=&quot;https://github.com/delano/gibbler/blob/v0.8.9/lib/gibbler.rb#L365&quot;&gt;Symbol&lt;/a&gt;, &lt;a href=&quot;https://github.com/delano/gibbler/blob/v0.8.9/lib/gibbler.rb#L400&quot;&gt;Hash&lt;/a&gt;, &lt;a href=&quot;https://github.com/delano/gibbler/blob/v0.8.9/lib/gibbler.rb#L440&quot;&gt;Array&lt;/a&gt;, etc.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'gibbler'&lt;/span&gt;

&lt;span class=&quot;s1&quot;&gt;'tea'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;gibbler&lt;/span&gt;                 &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; 6ef1ccef723f8f6c048399cfa5f46a781f559137&lt;/span&gt;
&lt;span class=&quot;ss&quot;&gt;:tea&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;gibbler&lt;/span&gt;                  &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; 4f7721e1a1e0a02f87b196fd78f94358293793c1&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:count&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;gibbler&lt;/span&gt;       &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; 19322962506419bd16d9de2ab3d1e5ec0772c4e6&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'1'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;gibbler&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; b05b4fada2105f0f9547ae320423deba729abe53&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Gibbler works similarly to Git: for complex objects, it dives depth-first and creates digests for each object and at each level creates a summary digest. The final digest is based on the summaries for each element.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;gibbler&lt;/span&gt;          &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; d1cf67fb93ec51885e7c74e4b3a3d5ef3aad2bf9&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;gibbler&lt;/span&gt;             &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; 18410df1574242b2730144ed483930072e49bd23&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;gibbler&lt;/span&gt;           &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; a05a76617a3b848060e6e8024e9c38a264dbd31b&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;gibbler&lt;/span&gt;         &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; b32e17d4bf10eb7101153703511d08de4509e0ce&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;You can also include gibbler in your own objects with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Gibbler::Complex&lt;/code&gt; which will create the hash based on the values of the instance variables:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Email&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Gibbler&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Complex&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;attr_accessor&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:subject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:content&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@subject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@content&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;msg1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;             
&lt;span class=&quot;n&quot;&gt;msg2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'d@example.com'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'t@example.com'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Hello'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Long time no see!'&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;msg1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;gibbler&lt;/span&gt;                  &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; 2667ed303e2e2cc307d49301acd7575ea3f90f2e&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;msg2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;gibbler&lt;/span&gt;                  &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; 328dfe801c2563e31aa9a2b4831fa182f5e41dfd&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;By the way, if you prefer literal method names, you can require &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gibbler/aliases&lt;/code&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'gibbler/aliases'&lt;/span&gt;
&lt;span class=&quot;s1&quot;&gt;'tea'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;digest&lt;/span&gt;                  &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; 6ef1ccef723f8f6c048399cfa5f46a781f559137&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;a-few-examples-of-using-hashes-in-your-code&quot;&gt;A few examples of using hashes in your code&lt;/h2&gt;

&lt;h3 id=&quot;know-when-a-complex-object-has-changed&quot;&gt;Know when a complex object has changed&lt;/h3&gt;

&lt;p&gt;When you store a record to your database, keep track of the latest hash. Later on, you can check that value to determine whether the contents of the object have changed without checking each field individually. You can also use the value of the hash to detect and prevent duplicate content. Here’s one example:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Article&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Gibbler&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Complex&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;attr_accessor&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:author&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:checksum&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;gibbler&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:author&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:content&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@author&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@content&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;changed?&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@checksum&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gibbler&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;article&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Article&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'jodie'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Chicken Soup'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'...'&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;article&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;checksum&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;article&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;gibbler&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;article&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;save&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Later on, in another process... &lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;article&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;content&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;and it was delicious.&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;article&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;changed?&lt;/span&gt;              &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; true&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;detect-duplicate-messages&quot;&gt;Detect duplicate messages&lt;/h3&gt;

&lt;p&gt;You don’t need to store copies of an object to know if you’ve seen them before:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'t@example.com'&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;seen&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'cust1@example.com'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'cust2@example.com'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'cust1@example.com'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'A catchy subject'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Some interesting content.'&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;seen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;member?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;gibbler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# cust1 has already received that specific email&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;next&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;seen&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;gibbler&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;find-data-without-storing-an-index&quot;&gt;Find data without storing an index&lt;/h3&gt;

&lt;p&gt;I use this approach extensively for &lt;a href=&quot;https://www.blamestella.com/&quot;&gt;Stella&lt;/a&gt; (my web monitoring service). When a customer runs a checkup, it creates a testplan to represent the site and page being tested. I create a new instance of the object every time, but because the digest for a given testplan is always the same I know where the object is stored without looking it up the based on the URI. As well, I include the customer ID in the digest calculation so that a each customer has their own instance of the testplan. You can see an example of that here:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;A testplan created from &lt;a href=&quot;https://www.blamestella.com/plan/599070ec766959286b71&quot;&gt;my account&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;A testplan created by an &lt;a href=&quot;https://www.blamestella.com/plan/e64fa9d4e3d24ce60440&quot;&gt;anonymous customer&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Notice that the list of recent checkups is different for each. I don’t need to do anything special for this. It’s just a freebie that comes along with using these hashes.&lt;/p&gt;

&lt;h3 id=&quot;know-which-local-objects-to-sync-remotely&quot;&gt;Know which local objects to sync remotely&lt;/h3&gt;

&lt;p&gt;If you have data in one location that you need to synchronize remotely (database records, files, etc) you can use the hashes to determine which objects need to be sent over. This is exactly how git determines what it needs to send to or receive from a remote repo. Of course you could simply keep track of the record IDs (in the case of a database) but by using hashes you get duplicate detection for free.&lt;/p&gt;

&lt;h3 id=&quot;maintain-an-index-pointer-for-an-array-without-storing-the-contents&quot;&gt;Maintain an index pointer for an Array without storing the contents&lt;/h3&gt;

&lt;p&gt;This example can seem arcane but I’ve found it useful on more than one occasion. Let’s say you have a list of values and you want to always process them in sequence. And for whatever reason you don’t store the values locally but every time you see this array of values you want to continue processing at the appropriate element.&lt;/p&gt;

&lt;p&gt;With hashes it’s simple: create an index using the gibbler hash of the array. It will always be the same as long as the values and the order of the values are the same (you could optionally create the hash after sorting the array).&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;indexes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;times&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;people&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;%w[dave john candace]&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# inside the loop to simulate different arrays&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;indexes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;people&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;gibbler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;indexes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;people&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;gibbler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;indexes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;people&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;gibbler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;indexes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;people&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;gibbler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;people&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;size&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;current_idx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;indexes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;people&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;gibbler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; 
  &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;people&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;current_idx&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Output:&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# dave&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# john&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# candace&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# dave&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# john&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;There are many more uses for hashes in your Ruby codes. I’m interested to hear some. Do you implement them in your projects?&lt;/p&gt;

&lt;h2 id=&quot;installing-gibbler&quot;&gt;Installing Gibbler&lt;/h2&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gem install gibbler
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/delano/gibbler&quot;&gt;code&lt;/a&gt; at Github&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://rubygems.org/gems/gibbler&quot;&gt;gem&lt;/a&gt; on Rubyforge&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://goldensword.ca/gibbler/&quot;&gt;documentation&lt;/a&gt; via RDocs&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.rubypulse.com/episode-0.3-gibbler.html&quot;&gt;screencast&lt;/a&gt; by Alex Peuchert&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;mini-faq&quot;&gt;Mini-F.A.Q.&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Can digests be made unique per application?&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yep. Set &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Gibbler.secret&lt;/code&gt; to anything, preferably something long.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;ss&quot;&gt;:kimmy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;gibbler&lt;/span&gt;                &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; 52be7494a602d85ff5d8a8ab4ffe7f1b171587df&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;Gibbler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;secret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'4cea880a75df6c8b1fa2'&lt;/span&gt;

&lt;span class=&quot;ss&quot;&gt;:kimmy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;gibbler&lt;/span&gt;                &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; 0f71d5813687cb07f8b6be5389e636962f49e213&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;What if attributes are added or removed to a class?&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gibbler&lt;/code&gt; class method to explicitly define the names and order of variables you want to use for the digest.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Email&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Gibbler&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Complex&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;gibbler&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:subject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:content&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;# only these fields will be considered&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'d@example.com'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'t@example.com'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Hello'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Long time no see!'&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;gibbler&lt;/span&gt;                   &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; 7f68056cf34cd42cbb3dee1f81535100ae783fe9&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'t2@example.com'&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;msg2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;gibbler&lt;/span&gt;                  &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; 7f68056cf34cd42cbb3dee1f81535100ae783fe9&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Can I use something other than SHA-1?&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yep, you can change the digest type globally or per call.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;ss&quot;&gt;:a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;gibbler&lt;/span&gt;                     &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; cd55a626c21b5580141442e789201e7e64276da9&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;Gibbler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;digest_type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Digest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;MD5&lt;/span&gt;
&lt;span class=&quot;ss&quot;&gt;:a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;gibbler&lt;/span&gt;                     &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; ef8de1a0d178ce85999a4b54840c21e0&lt;/span&gt;

&lt;span class=&quot;ss&quot;&gt;:a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;gibbler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Digest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;SHA256&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;     &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; f5fa26a66724c32df25f872fd691dd18e03cc2347a...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;You can also shorten and change the base of the digest:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;ss&quot;&gt;:kimmy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;gibbler&lt;/span&gt;                &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; 52be7494a602d85ff5d8a8ab4ffe7f1b171587df&lt;/span&gt;
&lt;span class=&quot;ss&quot;&gt;:kimmy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;gibbler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;shorten&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; 52be7494a602d85ff5d8&lt;/span&gt;
&lt;span class=&quot;ss&quot;&gt;:kimmy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;gibbler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;shorten&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; 52be7494a6&lt;/span&gt;
&lt;span class=&quot;ss&quot;&gt;:kimmy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;gibbler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;36&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;       &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; 9nydr6mpv6w4k8ngo3jtx0jz1n97h7j&lt;/span&gt;
&lt;span class=&quot;ss&quot;&gt;:kimmy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;gibbler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;       &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; 472384540402900668368761869477227308873774630879&lt;/span&gt;
&lt;span class=&quot;ss&quot;&gt;:kimmy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;gibbler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_i&lt;/span&gt;           &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; 472384540402900668368761869477227308873774630879&lt;/span&gt;
&lt;span class=&quot;ss&quot;&gt;:kimmy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;gibbler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; 101001010111110011101001001010010100110000...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

</content>
 </entry>
 
 <entry>
   <title>An update on yesterday's Stella outage (it was the Redis configuration)</title>
   <link href="http://solutious.com/blog/2011/03/10/update-on-stella-outage/"/>
   <updated>2011-03-10T00:00:00+00:00</updated>
   <id>http://solutious.com/blog/2011/03/10/update-on-stella-outage</id>
   <content type="html">&lt;p&gt;After I reported on the Stella &lt;a href=&quot;http://solutious.com/blog/2011/03/09/morning-stella-outage/&quot;&gt;outage yesterday&lt;/a&gt;, I did a bit more investigation and made a few changes to the operations of the site. To recap, yesterday at 9am PST the site became unresponsive and the background workers stopped running. I also couldn’t SSH in to the main backend machine and ultimately had to reboot it to get back in. After looking into it further, it looks like there were multiple factors at play.&lt;/p&gt;

&lt;h2 id=&quot;root-cause-revisited&quot;&gt;Root Cause, revisited&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Memory swapping and blocking&lt;/em&gt;. There was a conflict between the hourly backup process and the regular operation of the site. The hourly cronjob is simple: it copies the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;redis.rdb&lt;/code&gt; file, gzips it, encrypts it, and uploads it to S3. The conflict arose during the copy. Redis was configured to run a background save every 5 minutes to the same &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;redis.db&lt;/code&gt;. What I didn’t realize is that redis blocks the bgsave while that file is being copied. That file had grown a lot with the additional traffic over the past few weeks. I didn’t notice this issue previously because the cp and bgsave commands ran pretty quickly. With so much more data, both take longer so it was only a matter of time that this would happen.&lt;/p&gt;

&lt;h2 id=&quot;operational-changes&quot;&gt;Operational Changes&lt;/h2&gt;

&lt;p&gt;I made the following changes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Disabled background saves in Redis&lt;/li&gt;
  &lt;li&gt;Enabled append only persistence&lt;/li&gt;
  &lt;li&gt;Rewrote the hourly backup to run explicitly run a Redis background save&lt;/li&gt;
  &lt;li&gt;Added an hourly process to tidy unneeded data to keep the backups smaller&lt;/li&gt;
  &lt;li&gt;Added a nightly process to run bgrewriteaof to keep the append only file tidy&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;the-ssh-issue&quot;&gt;The SSH issue&lt;/h3&gt;

&lt;p&gt;There was still the issue of the hanging SSH connection. Before the outage and after I rebooted the machine, SSH was fine. Also, I was able to open a connection to the redis server the entire time so it wasn’t the network. I’m not 100% sure but I have a suspicion that it was a kernel problem. That suspicion is based entirely on several modprobe errors in the system console (missing modules). The machine was running an EBS instance type. I have had miscellaneous boot and connection problems with the EBS instance types so I decided to go back to a trusty old instance-store machine image. I built a new machine image and launched a new instance that replaced the previous machine.&lt;/p&gt;

&lt;p&gt;These changes have been in production for the past few hours. I’ll report back if I need to make any further modifications.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Morning Stella outage</title>
   <link href="http://solutious.com/blog/2011/03/09/morning-stella-outage/"/>
   <updated>2011-03-09T00:00:00+00:00</updated>
   <id>http://solutious.com/blog/2011/03/09/morning-stella-outage</id>
   <content type="html">&lt;p&gt;&lt;em&gt;Update: I posted &lt;a href=&quot;http://solutious.com/blog/2011/03/10/update-on-stella-outage/&quot;&gt;a follow-up&lt;/a&gt; on this outage.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.blamestella.com/&quot;&gt;Stella&lt;/a&gt; was down for about an hour and a half this morning, including checkups and monitors. I received a notification at 9am (PST) and the site returned to normal at 10:40am. Here is a screenshot of  &lt;a href=&quot;http://status.blamestella.com&quot;&gt;status.blamestella.com&lt;/a&gt; form this morning:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://solutious.com/blog/assets/2011-q1/bs-outage-03-09.png&quot;&gt;&lt;img src=&quot;http://solutious.com/blog/assets/2011-q1/bs-outage-03-09-s.png&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;the-symptoms&quot;&gt;The symptoms&lt;/h3&gt;

&lt;p&gt;The web servers were not responding and the master backend machine was not available via SSH (I could connect but it would hang after authenticating). The connection to Redis was not affected.&lt;/p&gt;

&lt;h3 id=&quot;the-cause&quot;&gt;The cause&lt;/h3&gt;

&lt;p&gt;I couldn’t verify that there was a single root cause. I couldn’t SSH in to the machine until after it was rebooted but it looks like something happened while Redis was running a background save. The only access I had was through &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;redis-cli&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;redis&amp;gt; bgsave
(error) ERR Background save already in progress
redis&amp;gt; save
(error) ERR Background save already in progress
redis&amp;gt; info 
...
aof_enabled:0
changes_since_last_save:67162
bgsave_in_progress:1
used_memory_human:2.21G
mem_fragmentation_ratio:1.44
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;My thinking at the time was that the process was swapping to VM so I waited patiently (not so patiently actually) to see if it would finish. There’s 7.5GB of RAM and Redis was only using about 2.5GB so there shouldn’t have been a need to swap but it’s possible (I’ve noticed that the redis-server process has used as much as 1GB more than what it report via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;info&lt;/code&gt;). As you can see there was some data in memory that hadn’t been written to disk yet so that was my top priority (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;changes_since_last_save&lt;/code&gt;). After about 20 minutes it was clear that there was something else going on and my top priority switched to getting the site back up. The data is stored on an EBS volume so my guess is that there was degraded IO performance. To be clear, I don’t suspect it was an issue with Redis itself. However, that still doesn’t explain why I couldn’t login via SSH so it’s possible there was a network issue at the same time (which I’ve experienced before in other EC2 available zones).&lt;/p&gt;

&lt;p&gt;At that point I made the decision to reboot the machine. I also started the process of provisioning a new backend machine using the most recent backup (which was created an hour earlier). I did these in parallel in the event that the existing machine did not come back up. It did and after it ran an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fsck&lt;/code&gt; I was able to get into the machine. I brought redis up, tested it, and then started the workers (which do the monitoring). Then I brought up the site after a few minutes.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: in the report you can see that the site came up briefly at 10am (PST). This was before the backend machine was restarted. The web servers could read and write to Redis but the monitoring and checkups jobs were not running.&lt;/em&gt;&lt;/p&gt;

&lt;h3 id=&quot;next-steps&quot;&gt;Next steps&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Switch to append-only backups to prevent the need for epic writes.&lt;/li&gt;
  &lt;li&gt;Create and practice a new recovery process to provision a new machine right away which can run off of a snapshot of the master’s EBS volume.&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>How I handled the traffic from a single Smashing Magazine tweet</title>
   <link href="http://solutious.com/blog/2011/02/11/smashingmag-tweet/"/>
   <updated>2011-02-11T00:00:00+00:00</updated>
   <id>http://solutious.com/blog/2011/02/11/smashingmag-tweet</id>
   <content type="html">&lt;p&gt;Smashing Magazine &lt;a href=&quot;http://twitter.com/smashingmag/status/35736314334814208&quot;&gt;tweeted about Stella&lt;/a&gt; yesterday. It generated a lot of traffic and quality feedback (&lt;a href=&quot;/blog/assets/2011-q1/backtype-2011-02-10.png&quot;&gt;around 130 tweets&lt;/a&gt;) so I wanted to write a bit about what I learned. I was away from the helm at the time so there were definitely a few lessons learned!&lt;/p&gt;

&lt;p class=&quot;graphic&quot;&gt;&lt;a href=&quot;http://twitter.com/smashingmag/status/35736314334814208&quot;&gt;&lt;img src=&quot;/blog/assets/2011-q1/smashingmagtweet.png&quot; alt=&quot;Smashing Magazine Tweet - February 10th, 2011&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span class=&quot;graphicSubtext&quot;&gt;A tweet by &lt;a href=&quot;http://www.smashingmagazine.com/&quot; title=&quot;Smashing Magazine&quot;&gt;Smashing Magazine&lt;/a&gt; on February 10th, 2011&lt;/span&gt;&lt;/p&gt;

&lt;h2 id=&quot;the-numbers&quot;&gt;The Numbers!&lt;/h2&gt;

&lt;p&gt;I was surprised by how much activity can be generated from a single tweet.&lt;/p&gt;

&lt;h4 id=&quot;in-the-first-24-hours&quot;&gt;In the first 24 hours&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;2629 visitors.&lt;/li&gt;
  &lt;li&gt;4018 checkups.&lt;/li&gt;
  &lt;li&gt;54 signups (2% conversion).&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;the-next-day-so-far-midday&quot;&gt;The next day (so far, midday)&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;449 visitors.&lt;/li&gt;
  &lt;li&gt;889 checkups.&lt;/li&gt;
  &lt;li&gt;9 signups. (2% conversion)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The 2% conversion rate is consistent with the burst of traffic last month from &lt;a href=&quot;http://news.ycombinator.com/item?id=2092155&quot;&gt;Hacker News&lt;/a&gt;. You can see both spikes below in the chart from &lt;a href=&quot;http://reinvigorate.net/&quot;&gt;Reinvigorate&lt;/a&gt;. Stella was also on &lt;a href=&quot;http://designfridge.co.uk&quot;&gt;Designfridge.co.uk&lt;/a&gt; earlier this week.&lt;/p&gt;

&lt;p class=&quot;graphic&quot;&gt;&lt;a href=&quot;/blog/assets/2011-q1/visitors-2011-02-10.png&quot;&gt;&lt;img src=&quot;/blog/assets/2011-q1/visitors-s-2011-02-10.png&quot; alt=&quot;Reinvigorate Stats - February 10th, 2011&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span class=&quot;graphicSubtext&quot;&gt;&lt;/span&gt;&lt;/p&gt;

&lt;h2 id=&quot;what-went-well&quot;&gt;What went well&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;It only took me about 15 minutes to get the site in order once I was able to get in front of my laptop. In that time, I added another front-end machine and added a couple more background workers.&lt;/li&gt;
  &lt;li&gt;Morton and Tucker are working really well in multiple ways. I tried to respond to every criticism and I spread the effort between &lt;a href=&quot;http://twitter.com/mortonblamey&quot;&gt;Morton&lt;/a&gt;, &lt;a href=&quot;http://twitter.com/tucker1927&quot;&gt;Tucker&lt;/a&gt;, &lt;a href=&quot;http://twitter.com/blamestella&quot;&gt;@blamestella&lt;/a&gt;, and &lt;a href=&quot;http://twitter.com/solutious&quot;&gt;my account&lt;/a&gt; so that I wouldn’t overwhelm any one feed with a stream of replies. I (or Morton, rather) successfully turned, &lt;a href=&quot;http://twitter.com/bibinex/status/35736991966433280&quot;&gt;“It takes a while to load. How’s that for #irony?”&lt;/a&gt; into:&lt;/li&gt;
&lt;/ul&gt;

&lt;p class=&quot;graphic&quot;&gt;&lt;a href=&quot;http://twitter.com/bibinex/status/35789702397169664&quot;&gt;&lt;img src=&quot;/blog/assets/2011-q1/bibinextweet-2011-02-10.png&quot; alt=&quot; - February 10th, 2011&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span class=&quot;graphicSubtext&quot;&gt;&lt;/span&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Short, interesting tag lines are effective. It seems obvious now but “is your site fast?” is the result of about 6 months of iteration. It’s a good tagline because it’s very short but it’s immediately apparent whether Stella would be useful to you. By making your own strong tagline, you’re also making it easier for people to tell your story.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;em&gt;Edit: I also need to give a huge shout out to the guys at &lt;a href=&quot;http://stillbrandworks.com&quot;&gt;the Still Brandworks&lt;/a&gt;. They’re the heavy-duty muscle behind the UI/UX which is generating a lot of the positive attention!&lt;/em&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;what-could-have-gone-better&quot;&gt;What could have gone better&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Well, the ideal scenario involves the site remaining fast and responsive! The site was grinding for about an hour before I could tend to it. There were also a number of precautionary rate limiters that were set too conservatively (eg. the number of checkups that can be run over a given period of time). I applied a couple short-terms fixes for both issues and have a longer-term plan in the works.&lt;/li&gt;
&lt;/ul&gt;

&lt;p class=&quot;graphic&quot;&gt;&lt;a href=&quot;/blog/assets/2011-q1/status-2011-02-10.png&quot;&gt;&lt;img src=&quot;/blog/assets/2011-q1/status-s-2011-02-10.png&quot; alt=&quot;Status for www.blamestella.com - February 10th, 2011&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span class=&quot;graphicSubtext&quot;&gt;&lt;/span&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;I got caught &lt;a href=&quot;http://twitter.com/solutious/status/35775534579322880&quot;&gt;away from the helm&lt;/a&gt;. &lt;em&gt;Someone should always be near the helm.&lt;/em&gt; Of course this is a challenge for a one-man shop and although I don’t expect this to be the case for long, I’m going to upgrade to a smartphone soon so I can make quick changes regardless of where I am. My &lt;a href=&quot;http://en.wikipedia.org/wiki/Samsung_SGH-X820&quot;&gt;Samsung x820&lt;/a&gt; has served me well over the years, but every journey must end.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Most of the signups were for the free plan. I need to do a better job getting people to the paid plans.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;in-summary&quot;&gt;In summary&lt;/h2&gt;

&lt;p&gt;I had a great time yesterday handling the new traffic and responding to feedback. Welcome to everyone who &lt;a href=&quot;https://www.blamestella.com/pricing&quot;&gt;signed up&lt;/a&gt; and thanks to all the people who tweeted, &lt;a href=&quot;https://www.blamestella.com/feedback&quot;&gt;sent feedback&lt;/a&gt; to Tucker, and ran checkups. And thank you &lt;a href=&quot;http://twitter.com/smashingmag&quot;&gt;@smashingmag&lt;/a&gt;!&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Why public monitoring is important</title>
   <link href="http://solutious.com/blog/2011/02/09/why-public-monitoring-is-important/"/>
   <updated>2011-02-09T00:00:00+00:00</updated>
   <id>http://solutious.com/blog/2011/02/09/why-public-monitoring-is-important</id>
   <content type="html">&lt;p&gt;There was an issue on Amazon EC2 yesterday that affected the response times for a non-trivial number of their customers (myself included). I first noticed the issue when &lt;a href=&quot;https://www.blamestella.com/&quot;&gt;blamestella.com&lt;/a&gt; began to get very slow (around 11:45 PST). I checked Stella’s public report for EC2 performance and other sites were having issues as well:&lt;/p&gt;

&lt;p class=&quot;graphic&quot;&gt;&lt;a href=&quot;/blog/assets/2011-q1/stella-ec2-status-2011-02-08.png&quot;&gt;&lt;img src=&quot;/blog/assets/2011-q1/stella-ec2-status-s-2011-02-08.png&quot; alt=&quot;Stella EC2 Report for February 8, 2011&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span class=&quot;graphicSubtext&quot;&gt;&lt;a href=&quot;https://www.blamestella.com/vendor/ec2/report&quot; title=&quot;EC2 Status - Stella&quot;&gt;Stella EC2 Report&lt;/a&gt; on February 8th, 2011&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The chart represents the average network latency (light grey), application latency (grey), and download time (dark grey) for all monitored sites on EC2 (71 separate sites at the time of this writing). You can see that the service is typically very stable with regards to HTTP response times so the issue yesterday was clearly an anomaly, but there was no information on Amazon’s status page:&lt;/p&gt;

&lt;h3 id=&quot;amazons-status-page&quot;&gt;Amazon’s Status Page&lt;/h3&gt;

&lt;p class=&quot;graphic&quot;&gt;&lt;a href=&quot;/blog/assets/2011-q1/aws-status-2011-02-08.png&quot;&gt;&lt;img src=&quot;/blog/assets/2011-q1/aws-status-s-2011-02-08.png&quot; alt=&quot;Amazon Web Services Status for February 8, 2011&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span class=&quot;graphicSubtext&quot;&gt;&lt;a href=&quot;http://status.aws.amazon.com/&quot;&gt;Amazon Web Services Status&lt;/a&gt; page on February 8th, 2011&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;I love Amazon. For them, this was probably an isolated problem that affected a relatively small number of their customers. However, the customers that it did affect were left in the dark. The natural response would be to assume that it’s a problem with your application until you start hearing reports for other sites. This is where the value of public monitoring becomes apparent and it’s one of the reasons I built Stella.&lt;/p&gt;

&lt;h2 id=&quot;leading-by-example&quot;&gt;Leading by example&lt;/h2&gt;

&lt;p&gt;Heroku is built on EC2 and their service was affected yesterday as well. They do a great job handling operational issues by being responsive and open with their customers. Yesterday was no exception:&lt;/p&gt;
&lt;p class=&quot;graphic&quot;&gt;&lt;a href=&quot;/blog/assets/2011-q1/heroku-status-2011-02-08.png&quot;&gt;&lt;img src=&quot;/blog/assets/2011-q1/heroku-status-s-2011-02-08.png&quot; alt=&quot;Heroku Status for February 8, 2011&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span class=&quot;graphicSubtext&quot;&gt;&lt;a href=&quot;http://status.heroku.com/&quot;&gt;Heroku Status&lt;/a&gt; page on February 8th, 2011&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Although they didn’t have answers as to the cause, simply demonstrating that they’re on top of things is reassuring and a sign of a responsible, well-run company.&lt;/p&gt;

&lt;h2 id=&quot;all-services-go-down&quot;&gt;All services go down&lt;/h2&gt;

&lt;p&gt;Public monitoring isn’t about highlighting the failures of a site or service. It’s about accepting the fact that all services go down from time to time. Public reports help site operators and they keep customers informed.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Gateway support for Rye, via Rye::Hop</title>
   <link href="http://solutious.com/blog/2011/01/29/rye-hop-gateway-support/"/>
   <updated>2011-01-29T00:00:00+00:00</updated>
   <id>http://solutious.com/blog/2011/01/29/rye-hop-gateway-support</id>
   <content type="html">&lt;p&gt;Thanks to a fork from &lt;a href=&quot;http://hashbangbash.com/&quot;&gt;Vincent Batts&lt;/a&gt;, Rye now has gateway support!&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rhop = Rye::Hop.new('firewall.lan')
rbox = Rye::Box.new('filibuster', :via =&amp;gt; rhop)
rbox.uptime     # =&amp;gt; 20:53  up 1 day,  1:52, 4 users
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Or:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rbox = Rye::Box.new 'filibuster', :via =&amp;gt; 'firewall.lan'
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Gateway support allows you to access machines through a tunnelled connection (similar to &lt;a href=&quot;https://github.com/net-ssh/net-ssh-gateway&quot;&gt;Net::SSH::Gateway&lt;/a&gt;). This functionality is available in the &lt;a href=&quot;https://github.com/delano/rye/tree/v0.9.3&quot;&gt;0.9.3 release&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;installation&quot;&gt;Installation&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gem install rye --version 0.9.3
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;about-rye&quot;&gt;About Rye&lt;/h3&gt;

&lt;p&gt;Rye is a Ruby library that provides a safe, simple way to access Unix shells. You create an instance of Rye::Box and the methods you call against it are mapped to shell commands over SSH.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rbox = Rye::Box.new('hostname')
rbox.pwd                               # =&amp;gt; &quot;/home/rye&quot;
rbox.uname :a                          # =&amp;gt; &quot;Darwin rye-stage 9.7.0 ...&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;With the block syntax, Rye looks a lot like a shell script.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rbox.batch do
  cd 'redis-2.0.0-rc3'
  configure
  make
  make 'install'
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;See the &lt;a href=&quot;https://github.com/delano/rye/&quot;&gt;Github repo&lt;/a&gt; for more examples.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Introducing Bone and the Bonery</title>
   <link href="http://solutious.com/blog/2010/12/20/introducing-bone-and-the-bonery/"/>
   <updated>2010-12-20T00:00:00+00:00</updated>
   <id>http://solutious.com/blog/2010/12/20/introducing-bone-and-the-bonery</id>
   <content type="html">&lt;p&gt;&lt;em&gt;Whoa, whoa, whoa, whoa, whoa. There’s still plenty of meat on that bone. Now you take this home, throw it in a pot, add some broth, a potato. Baby you got a stew goin’.&lt;/em&gt; – Carl Weathers&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://github.com/solutious/bone/raw/gh-pages/bone.png&quot; width=&quot;220&quot; height=&quot;186&quot; align=&quot;right&quot; border=&quot;0&quot; style=&quot;padding-left:30px; padding-bottom: 30px;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Configuration management is hard. A lot of stuff is hard, but you don’t mind because you expect it. Managing configuration on the other hand seems like such an innocent and simple problem. However, the solutions often turn to be horrible, debilitating nightmares. Part of the problem for me is that the tools are really complicated. That’s a bit unfair to say because at some point there is a reason for that complexity (large projects, large teams, etc). But when your team is just a few people strong and when you don’t have the resources to dedicate to specific tasks, it really helps to have simple, straight-forward tools.&lt;/p&gt;

&lt;p&gt;So when it comes to configuration, I use something a little more inline with Carl Weathers’ philosophy. It’s a command-line tool and Ruby library called &lt;a href=&quot;https://github.com/solutious/bone/&quot;&gt;Bone&lt;/a&gt;. I’ve been using it internally for about a year to store configuration and what I like to call &lt;em&gt;remote environment variables&lt;/em&gt;. It’s only version 0.3 so it’s very basic, almost to a fault. However, what it lacks in features in makes up for by endeavouring to never ruin your day.&lt;/p&gt;

&lt;h2 id=&quot;bone-remote-environment-variables&quot;&gt;Bone: Remote Environment Variables&lt;/h2&gt;

&lt;p&gt;It’s essentially the simplest possible key-value store. Here’s a taste:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;delano@localhost&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;bone &lt;span class=&quot;nb&quot;&gt;set &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;dbmaster&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;192.168.1.1
192.168.1.1

delano@prodfe&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;bone dbmaster
192.168.1.1&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The values you set on the command-line are available in your Ruby code like regular environment variables.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'bone'&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;Bone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:dbmaster&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; 192.168.1.1&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;Bone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:dbmaster&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'10.0.1.1'&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;Bone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:dbmaster&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; 10.0.1.1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;You can also pass values by STDIN.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;delano@localhost&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&amp;lt;path/2/redis_server.conf bone &lt;span class=&quot;nb&quot;&gt;set &lt;/span&gt;redisconf&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;!-- Do not remove this comment --&gt;

&lt;p&gt;I use bone everywhere. Some examples:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;I store all my configuration files in there so I can make one simple command to get a copy. (keys: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;redis-server-2.2&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nginx-0.7&lt;/code&gt;, etc…)&lt;/li&gt;
  &lt;li&gt;In backup scripts, I make a call to bone to store the latest path. (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bs-backup-latest&lt;/code&gt;)&lt;/li&gt;
  &lt;li&gt;I store the ip addresses of various machines so when I start new machines the scripts that on them will always grab the updated addresses. (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bs-redis-master&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bs-prod-fe&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;behind-the-scenes&quot;&gt;Behind the scenes&lt;/h2&gt;

&lt;p&gt;It works by communicating with an HTTP server, called &lt;a href=&quot;https://github.com/solutious/boned/&quot;&gt;Boned&lt;/a&gt; using a simple REST API. Since all the data is stored remotely, the values you set can be made available to any machine that can connect to the Boned server. The API is based on two regular environment variables: a token, which is like your username, and a secret which is used to sign each request (the signing is based on the one Amazon uses for EC2, S3, etc). There is a third environment variable to tell bone which server to use.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;# In your ~/.bashrc or equivalent...&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;BONE_SOURCE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;https://api.bonery.com/
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;BONE_TOKEN&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;YOURTOKEN
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;BONE_SECRET&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;sUp3R5eKru7&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;the-bonery&quot;&gt;The Bonery&lt;/h2&gt;

&lt;p&gt;I’ve also launched an alpha version of &lt;a href=&quot;http://bonery.com/&quot;&gt;The Bonery&lt;/a&gt; so you can try it out without running the server yourself.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://api.bonery.com/signup/alpha&quot; title=&quot;The Bonery | Remote Environment Variables&quot; style=&quot;color: #222; background-color: yellow; padding-left: 5px; padding-right: 5px&quot;&gt; GET YOUR API KEY &lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It’s alpha as a I mentioned, so don’t rely on it for production just yet. But get your key, throw in some variables, a file, some configuration, and baby you got a stew goin’!&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>The 70% Solution</title>
   <link href="http://solutious.com/blog/2010/10/18/the-70-percent-solution/"/>
   <updated>2010-10-18T00:00:00+00:00</updated>
   <id>http://solutious.com/blog/2010/10/18/the-70-percent-solution</id>
   <content type="html">&lt;p&gt;I used to joke with my team at &lt;a href=&quot;http://www.yellowpages.ca/&quot;&gt;YellowPages&lt;/a&gt;, “if you can’t make it great, make it just good enough”. It kept being a joke until I started my own company, when I realized that it was a reasonable approach to running a startup.&lt;/p&gt;

&lt;p&gt;Starting a company is very different than working in a larger organization. When you have a specific role, you can focus all of your attention on a limited set of tasks [1]. But in a startup, there’s too much to do and too few people to do it. It’s the amount of work and also the variety of tasks. There’s a lot to do outside of your areas of expertise so it’s easy to feel overwhelmed and under qualified.&lt;/p&gt;

&lt;p&gt;What didn’t work:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Working myself to exhaustion.&lt;/strong&gt; This obviously was not sustainable and it took an unreasonably long time to recover. It also didn’t increase the quality of my output.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Focusing on just a couple things.&lt;/strong&gt; I wrote some great code that I couldn’t build a service around. It was fun and I became a better programmer but again, it wasn’t sustainable.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Doing nothing.&lt;/strong&gt; This turned out to be the worst solution of the three. It sounded like a great idea and I got some rest but it’s no way to earn a living.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’ll be honest: I’m not &lt;a href=&quot;http://en.wikipedia.org/wiki/Bo_Jackson&quot;&gt;Bo Jackson&lt;/a&gt;. I realized that if I was going to feel good about my work and remain motivated over the long haul I’d need to redefine what it meant to be done something.&lt;/p&gt;

&lt;h2 id=&quot;just-good-enough-for-now&quot;&gt;Just good enough (for now)&lt;/h2&gt;

&lt;p&gt;Every endeavour has an &lt;em&gt;ideal&lt;/em&gt; outcome and an &lt;em&gt;actual&lt;/em&gt; outcome. My mistake was comparing the actual outcome with the ideal one in my head and feeling bad that I wasn’t living up to my own expectations. So I started evaluating my performance against 70% of the ideal – not in order to legitimize mediocre work but to be realistic.&lt;/p&gt;

&lt;p&gt;When you’re working on any sufficiently ambitious project, you need to find time somewhere. You can pretend you can do everything all the time and be exhausted. Or you can be honest with yourself and feel good about your work. You can always follow up with a second effort later on.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;So try the 70% solution.&lt;/em&gt; It’s surprising how much you can accomplish by consistently achieving modest goals.&lt;/p&gt;

&lt;p&gt;–&lt;/p&gt;

&lt;p&gt;[1] Depending on the culture of the organization that can change. I call it “responsibility creep”. It feels a lot like working at a startup without any of the benefits.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Don't waste time writing tests</title>
   <link href="http://solutious.com/blog/2010/09/07/do-not-waste-time-writing-tests/"/>
   <updated>2010-09-07T00:00:00+00:00</updated>
   <id>http://solutious.com/blog/2010/09/07/do-not-waste-time-writing-tests</id>
   <content type="html">&lt;p&gt;I don’t enjoy wasted effort. Not many people do. When it comes to testing the code I write, I’ve often felt like I was wasting my time. And sometimes I was. Not often, but enough that it got me thinking, &lt;em&gt;there’s got to be a better way.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;some-problems-i-have-with-tests-and-testing&quot;&gt;Some problems I have with tests and testing&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Writing tests for volatile code doesn’t help anyone.&lt;/strong&gt; Names are going to change. Entire namespaces will be added or removed. You want to feel free to do make those changes.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Test code looks nothing like the how the code is actually used.&lt;/strong&gt; Most test files look like crap. I’m sorry, but it’s true. Your code gets intertwined with stuff that has nothing to do with your project. There’s also a lot of repetition.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;It’s difficult to determine whether the time was well spent.&lt;/strong&gt; You definitely know when you should have spent more time testing (when something breaks) but it’s difficult to know when you’ve spent too much time. Or just enough. Or in the worst case scenario, you wrote a lot of tests, but not necessarily on the right areas.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Maintaining a test suite is a pain in the junk.&lt;/strong&gt; If you’re working on a large, well-established project then yeah, you’re going to need lots and lots of tests. That’s how you institutionalize quality and you probably have enough people to handle the workload. But if you have a small team or a rapidly changing project, that testing suite is going to bog you down.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;my-solution-treat-tests-as-sample-code&quot;&gt;My solution: treat tests as sample code&lt;/h2&gt;

&lt;p&gt;It’s the most simple solution I can think without going over: write code exactly as it’s used in the wild and put the test definitions in comments. That way all the code you see is code that could appear IRL. Even in the worst case scenario where I have no way to know whether the time was well spent, &lt;em&gt;the work doubles as documentation.&lt;/em&gt; That’s a huge win.&lt;/p&gt;

&lt;p&gt;To get this to work in Ruby, I wrote a library called &lt;a href=&quot;http://github.com/delano/tryouts&quot;&gt;Tryouts&lt;/a&gt;. (Thanks to &lt;a href=&quot;http://mynyml.com/&quot;&gt;Martin Aumont&lt;/a&gt; and &lt;a href=&quot;http://cloudhead.io/&quot;&gt;Alexis Sellier&lt;/a&gt; for working on various implementation ideas with me.)&lt;/p&gt;

&lt;p&gt;Here’s an example:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'rye'&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Setup&lt;/span&gt;
&lt;span class=&quot;vi&quot;&gt;@local_sandbox&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Rye&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sysinfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;tmpdir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'rye-tryouts'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;vi&quot;&gt;@lbox&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Rye&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Box&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'localhost'&lt;/span&gt;


&lt;span class=&quot;c1&quot;&gt;## upload file&lt;/span&gt;
&lt;span class=&quot;vi&quot;&gt;@lbox&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;file_upload&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'README.rdoc'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@local_sandbox&lt;/span&gt;
&lt;span class=&quot;vi&quot;&gt;@lbox&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;file_exists?&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@local_sandbox&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'README.rdoc'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#=&amp;gt; true&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;## download file&lt;/span&gt;
&lt;span class=&quot;vi&quot;&gt;@downloaded_file&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Rye&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sysinfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;tmpdir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'localfile'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;vi&quot;&gt;@lbox&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;file_download&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@local_sandbox&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'README.rdoc'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@downloaded_file&lt;/span&gt; 
&lt;span class=&quot;vi&quot;&gt;@lbox&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;file_exists?&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@downloaded_file&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#=&amp;gt; true&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;## download to StringIO&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;content&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@lbox&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;file_download&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@local_sandbox&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'README.rdoc'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;class&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#=&amp;gt; StringIO&lt;/span&gt;


&lt;span class=&quot;c1&quot;&gt;# Teardown&lt;/span&gt;
&lt;span class=&quot;vi&quot;&gt;@lbox&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@downloaded_file&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;span class=&quot;graphicSubtext&quot;&gt;An example of the &lt;a href=&quot;http://github.com/delano/tryouts&quot; title=&quot;Don't waste your time writing tests&quot;&gt;Tryouts&lt;/a&gt; test syntax that doubles as sample code. &lt;a href=&quot;http://github.com/delano/rye/tree/master/try/&quot; title=&quot;Rye: Safe, parallel access to Unix shells from Ruby&quot;&gt;More examples&lt;/a&gt;.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;And yep, it runs:&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;graphic&quot; src=&quot;/blog/assets/2010-q3/running-tryouts.png&quot; alt=&quot;Running Tryouts on the command line&quot; border=&quot;0&quot; /&gt;&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Notes on brand positioning statements</title>
   <link href="http://solutious.com/blog/2010/04/05/positioning-statements/"/>
   <updated>2010-04-05T00:00:00+00:00</updated>
   <id>http://solutious.com/blog/2010/04/05/positioning-statements</id>
   <content type="html">&lt;p&gt;A comment from &lt;a href=&quot;http://twitter.com/acroll&quot;&gt;Alistair Croll&lt;/a&gt; today made me realize I didn't have a brand positioning statement for one of the projects I'm working on. While creating one, I put some notes together and thought I would post them in case they're helpful for someone. If you don't have a brand positioning statement or you want to understand them better, definitely take a look at the links below too!&lt;/p&gt;

&lt;h2&gt;Definition&lt;/h2&gt;
&lt;p&gt;
  &lt;blockquote&gt;&lt;em&gt;A brand positioning statement describes the &quot;mental space&quot; a brand should occupy in the minds of a target audience. It serves as an internal document which guides most of a company's marketing communications strategies, programs and tactics. The brand positioning statement focuses on the elements and associations which meaningfully set a brand apart from the competition. It is typically constructed in the following format: &quot;To (target market), Brand X is the brand of (frame of reference) that (point of difference) because (reasons).&lt;/em&gt;&lt;/blockquote&gt;

  &lt;span class=&quot;graphicSubtext&quot;&gt;via &lt;a href=&quot;http://www.venturerepublic.com/resources/brand_glossary.asp&quot;&gt;Venture Republic&lt;/a&gt;&lt;/span&gt;
&lt;/p&gt;

&lt;h2&gt;Process&lt;/h2&gt;

&lt;p&gt;
  &lt;blockquote&gt;
  &lt;ol&gt;
    &lt;li&gt;Describe your customers &lt;span style=&quot;color: #999&quot;&gt;(so you know what's important to them)&lt;/span&gt;&lt;/li&gt;
    &lt;li&gt;Define yourself in terms of your competition &lt;span style=&quot;color: #999&quot;&gt;(to help you explain your product)&lt;/span&gt;&lt;/li&gt;
    &lt;li&gt;Explain your greatest benefit &lt;span style=&quot;color: #999&quot;&gt;(the one thing that's most important to your most important customers)&lt;/span&gt;&lt;/li&gt;
    &lt;li&gt;Put it together to create your Brand Positioning Statement&lt;/li&gt;
  &lt;/ol&gt;
  &lt;/blockquote&gt;
  &lt;span class=&quot;graphicSubtext&quot;&gt;via &lt;a href=&quot;http://www.wilsonweb.com/tools/danwilson-positioning-statement.htm&quot;&gt;Dan Wilson - Web Marketing Today&lt;/a&gt;&lt;/span&gt;
&lt;/p&gt;

&lt;h2&gt;Templates&lt;/h2&gt;
&lt;p&gt;
  &lt;blockquote&gt;
  &lt;span class=&quot;largeText&quot;&gt;FOR &lt;input class=&quot;defaultContent&quot; name=&quot;&quot; value=&quot;target audience&quot;/ &gt;,

  &lt;input class=&quot;defaultContent&quot; name=&quot;&quot; value=&quot;company name&quot;/ &gt;&lt;br/&gt;
  OFFERS &lt;input class=&quot;defaultContent&quot; size=&quot;30&quot; value=&quot;competitive frame of reference&quot; /&gt;&lt;br/&gt;

  THAT PROVIDES &lt;input class=&quot;defaultContent&quot; size=&quot;30&quot; value=&quot;greatest competitive advantage&quot;/ &gt;.&lt;/span&gt;
  &lt;/blockquote&gt;
  
  &lt;span class=&quot;graphicSubtext&quot;&gt;via &lt;a href=&quot;http://www.wilsonweb.com/tools/danwilson-positioning-statement.htm&quot;&gt;Dan Wilson - Web Marketing Today&lt;/a&gt;&lt;/span&gt;
&lt;/p&gt;

&lt;div class=&quot;topDots&quot; style=&quot;margin: 30px;&quot;&gt;&lt;/div&gt;
&lt;p&gt;
  &lt;blockquote&gt;
  &lt;span class=&quot;largeText&quot;&gt;OUR &lt;input class=&quot;defaultContent&quot; name=&quot;&quot; value=&quot;offering&quot;/ &gt;&lt;br/&gt;
  IS THE ONLY &lt;input class=&quot;defaultContent&quot; name=&quot;&quot; value=&quot;category&quot;/ &gt;&lt;br/&gt;
  THAT &lt;input class=&quot;defaultContent&quot; name=&quot;&quot; value=&quot;main benefit&quot;/ &gt;.&lt;/span&gt;
  &lt;/blockquote&gt;
  &lt;span class=&quot;graphicSubtext&quot;&gt;via the &lt;a href=&quot;http://www.smbmarketingguide.com/brand-strategy/branding-101-how-to-write-a-positioning-statement/&quot;&gt;Small Business Marketing Guide&lt;/a&gt;&lt;/span&gt;
&lt;/p&gt;

&lt;div class=&quot;topDots&quot; style=&quot;margin: 30px;&quot;&gt;&lt;/div&gt;
&lt;p&gt;
  &lt;blockquote&gt;
  &lt;span class=&quot;largeText&quot;&gt;FOR &lt;input class=&quot;defaultContent&quot; name=&quot;&quot; value=&quot;target audience&quot;/&gt;&lt;br/&gt;
  &lt;input class=&quot;defaultContent&quot; name=&quot;&quot; value=&quot;your product name&quot;/ &gt;
  IS A  &lt;input class=&quot;defaultContent&quot; name=&quot;&quot; value=&quot;category&quot;/ &gt;&lt;br/&gt;
  WHICH PROVIDES &lt;input class=&quot;defaultContent&quot; size=&quot;30&quot; value=&quot;main benefit&quot; /&gt;&lt;br/&gt;

  UNLIKE &lt;input class=&quot;defaultContent&quot; size=&quot;20&quot; value=&quot;main competitor&quot;/ &gt;&lt;br/&gt;
  WHICH PROVIDES &lt;input class=&quot;defaultContent&quot; size=&quot;25&quot; value=&quot;competitor's main benefit&quot;/ &gt;.&lt;/span&gt;
  &lt;/blockquote&gt;
  
  &lt;span class=&quot;graphicSubtext&quot;&gt;via the &lt;a href=&quot;http://www.smbmarketingguide.com/brand-strategy/branding-101-how-to-write-a-positioning-statement/&quot;&gt;Small Business Marketing Guide&lt;/a&gt;&lt;/span&gt;
&lt;/p&gt;

&lt;div class=&quot;topDots&quot; style=&quot;margin: 30px;&quot;&gt;&lt;/div&gt;

&lt;p&gt;
  &lt;blockquote&gt;
  &lt;span class=&quot;largeText&quot;&gt;FOR &lt;input class=&quot;defaultContent&quot; name=&quot;&quot; value=&quot;target audience&quot;/ &gt;
  THAT &lt;input class=&quot;defaultContent&quot; name=&quot;&quot; value=&quot; have a specific need&quot;/ &gt;, &lt;br/&gt;
  WE OFFER &lt;input class=&quot;defaultContent&quot; name=&quot;&quot; value=&quot;your name&quot;/ &gt;. &lt;br/&gt;

  UNLIKE &lt;input class=&quot;defaultContent&quot; name=&quot;&quot; value=&quot;main competitor&quot;/ &gt;,
  &lt;input class=&quot;defaultContent&quot; name=&quot;&quot; value=&quot;your name&quot;/ &gt; PROVIDES
  &lt;input class=&quot;defaultContent&quot; name=&quot;&quot; value=&quot;your main benefit&quot;/ &gt;
  THAT &lt;input class=&quot;defaultContent&quot; name=&quot;&quot; value=&quot;allows users to...&quot;/ &gt;.&lt;/span&gt;
  &lt;/blockquote&gt;
  
  &lt;span class=&quot;graphicSubtext&quot;&gt;adapted from &lt;a href=&quot;http://news.ycombinator.com/item?id=360069&quot;&gt;a comment by Thomas Ptacek&lt;/a&gt;&lt;/span&gt;
&lt;/p&gt;



&lt;script type=&quot;text/javascript&quot;&gt;
Cufon.replace('.entry .largeText');
$('input.defaultContent').focus( function() { 
	$(this).removeClass('defaultContent');
});
&lt;/script&gt;</content>
 </entry>
 
 <entry>
   <title>Automate SSH key authorization with Rye</title>
   <link href="http://solutious.com/blog/2010/02/25/ssh-key-authorization-with-rye/"/>
   <updated>2010-02-25T00:00:00+00:00</updated>
   <id>http://solutious.com/blog/2010/02/25/ssh-key-authorization-with-rye</id>
   <content type="html">&lt;p&gt;I got annoyed with manually &lt;a href=&quot;http://sial.org/howto/openssh/publickey-auth/&quot;&gt;authorizing my public keys&lt;/a&gt; to &lt;tt&gt;~/.ssh/authorized_keys&lt;/tt&gt; and &lt;tt&gt;~/.ssh/authorized_keys2&lt;/tt&gt; so I added a feature to &lt;a href=&quot;http://github.com/delano/rye&quot;&gt;rye&lt;/a&gt; to automate the process.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ rye authorize user@example.com
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The expected output looks something like this:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ rye authorize user@example.com
Authorizing user@example.com
Passwordless login failed for user
Password: ************
Added public keys for: 
/home/user/.ssh/id_dsa
/home/user/.ssh/id_rsa
Now try: ssh user@example.com
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;installation&quot;&gt;Installation&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ gem install -V rye
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can generate an SSH keypair with the following command iff you don’t already have one (by default they’re installed to &lt;tt&gt;~/.ssh/id_rsa&lt;/tt&gt; or &lt;tt&gt;~/.ssh/id_dsa&lt;/tt&gt;):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ ssh-keygen -t rsa
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</content>
 </entry>
 
 <entry>
   <title>The Secret of Object#to_s</title>
   <link href="http://solutious.com/blog/2009/09/22/secret-of-object-to_s/"/>
   <updated>2009-09-22T00:00:00+00:00</updated>
   <id>http://solutious.com/blog/2009/09/22/secret-of-object-to_s</id>
   <content type="html">&lt;p&gt;There’s something about Ruby that I’ve wanted to know for a long time: &lt;em&gt;where does the hexadecimal value in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#&amp;lt;Object:0x000001009e60f8&amp;gt;&lt;/code&gt; come from?&lt;/em&gt; Today I finally went looking for the answer.&lt;/p&gt;

&lt;h2 id=&quot;when-in-doubt-look-at-the-code&quot;&gt;When in doubt, look at the code&lt;/h2&gt;

&lt;p&gt;The documentation for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Object#to_s&lt;/code&gt; tells us that the value is based on the object id: “Returns a string representing obj. The default &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;to_s&lt;/code&gt; prints the object‘s class and an encoding of the object id.”&lt;/p&gt;

&lt;p&gt;Looking at the source code for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;to_s&lt;/code&gt;, we can see that it’s using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sprintf&lt;/code&gt; to create the hexadecimal value. From &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;object.c&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;cm&quot;&gt;/* Ruby 1.9 */&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;rb_sprintf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;#&amp;lt;%s:%p&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/* Ruby 1.8 */&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;snprintf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RSTRING&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;#&amp;lt;%s:0x%lx&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;span class=&quot;graphicSubtext&quot;&gt;You can find this code in the Ruby source code in the file ruby-VERSION/object.c&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Now, Ruby’s sprintf doesn’t support &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%p&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%lx&lt;/code&gt; but it does support &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%x&lt;/code&gt;. However, there’s obviously more to the story because the values still don’t match up:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;&quot;#&amp;lt;%s:0x%x&amp;gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;object_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; #&amp;lt;Object:0x80813ff4&amp;gt;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;                                         &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; #&amp;lt;Object:0x101027fe8&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;So what do we need to do to the object id to get the real hexadecimal value?&lt;/p&gt;

&lt;h2 id=&quot;a-tiny-calculation&quot;&gt;A tiny calculation&lt;/h2&gt;

&lt;p&gt;If we take a look at the hexadecimal values in plain-old decimal, the answer becomes obvious. Can you see it?&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;s2&quot;&gt;&quot;0x80813ff4&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;hex&lt;/span&gt;                                 &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; 2155954164&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;&quot;0x101027fe8&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;hex&lt;/span&gt;                                &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; 4311908328&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;All we have to do is double it!&lt;/p&gt;

&lt;h2 id=&quot;and-the-answer-is&quot;&gt;And the answer is…&lt;/h2&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;s2&quot;&gt;&quot;#&amp;lt;%s:0x%x&amp;gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;object_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; #&amp;lt;Object:0x101027fe8&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;em&gt;Note: I’ve created a tiny project called &lt;a href=&quot;http://github.com/delano/hexoid/&quot;&gt;Hexoid&lt;/a&gt; to handle the minor formatting difference between Ruby 1.8 and 1.9.&lt;/em&gt;&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Releasing with Rudy</title>
   <link href="http://solutious.com/blog/2009/09/14/releasing-with-rudy/"/>
   <updated>2009-09-14T00:00:00+00:00</updated>
   <id>http://solutious.com/blog/2009/09/14/releasing-with-rudy</id>
   <content type="html">&lt;p&gt;I have about &lt;a href=&quot;http://github.com/delano/&quot;&gt;10 active&lt;/a&gt; &lt;a href=&quot;http://github.com/solutious/&quot;&gt;opensource projects&lt;/a&gt;. I’m lucky because most of them aren’t that popular so there’s not a lot of overhead. Beyond other people using your work there are some significant advantages in maintaining projects as opensource (I’ll talk more about that in a future post). That said, there is additional effort involved so I’ve automated some tasks with &lt;a href=&quot;/projects/rudy/&quot;&gt;Rudy&lt;/a&gt; to reduce the repetitive tasks. One such task is the release process.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Minor warning: The following is specific to Ruby development on Linux/Unix with git because that where I do most of my work. If you’ve created configurations for other languages (including projects on Windows) let me know and I’ll post them or include them in &lt;a href=&quot;http://github.com/rudy/arcade/&quot;&gt;the arcade&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;my-rudy-configuration&quot;&gt;My Rudy Configuration&lt;/h2&gt;

&lt;p&gt;One of the core features of Rudy is the &lt;em&gt;routines&lt;/em&gt; configuration. A routine is like a really concise Rake task that can be associated to a particular machine role. A little known fact is that Rudy also supports defining global routines which are available to all machines.&lt;/p&gt;

&lt;p&gt;Rudy looks for global routines in two places:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.rudy/&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/&lt;/code&gt; (linux only)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I put the following configuration into a file called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.rudy/release-routines.rb&lt;/code&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;commands&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;allow&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:rm&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;routines&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  
  &lt;span class=&quot;n&quot;&gt;publish&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;before&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:package_test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:publish_docs&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;project&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;basename&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pwd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;first&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;PUBLISH &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;project&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;vg&quot;&gt;$/&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;after&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:publish_github&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:publish_gem&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
  &lt;span class=&quot;n&quot;&gt;package_test&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Creating Test package...'&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;rake&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'package'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'clean'&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
  &lt;span class=&quot;n&quot;&gt;publish_docs&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;before&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:publish_rubyforge_docs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:publish_github_docs&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
  &lt;span class=&quot;n&quot;&gt;publish_rubyforge_docs&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Updating Rubyforge docs...'&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;rake&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'publish:rdoc'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'clean'&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
  &lt;span class=&quot;n&quot;&gt;publish_github_docs&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;rake&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'rdoc'&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;file_exists?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'doc'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Updating Github Pages...'&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'checkout'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'gh-pages'&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'files'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'classes'&lt;/span&gt; 
        &lt;span class=&quot;n&quot;&gt;unsafely&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mv&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'doc/*'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'.'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'doc'&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'add'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'.'&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'commit'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Updated docs'&lt;/span&gt;
        
        &lt;span class=&quot;n&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'checkout'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'master'&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'push'&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'No docs directory'&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
  &lt;span class=&quot;n&quot;&gt;publish_github&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Pushing to GitHub...'&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'tag'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'latest'&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'push'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'--all'&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'push'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'--tags'&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
  &lt;span class=&quot;n&quot;&gt;publish_gem&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Publishing Rubyforge gem...'&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;rake&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'publish:gem'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'clean'&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;span class=&quot;graphicSubtext&quot;&gt;The Rudy configuration I use to create releases of my open source projects. &lt;/span&gt;&lt;/p&gt;

&lt;h2 id=&quot;my-release-process&quot;&gt;My Release Process&lt;/h2&gt;

&lt;p&gt;With the configuration above in place, I can run the release routines I created from any directory on my machine. But before I run the automated process, there are a few tasks that still require manual attention.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Update the change log&lt;/li&gt;
  &lt;li&gt;Update file manifest and dependencies in the gemspec file (if necessary)&lt;/li&gt;
  &lt;li&gt;Increment the release number&lt;/li&gt;
  &lt;li&gt;Commit all local changes&lt;/li&gt;
  &lt;li&gt;Create a release tag&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then I run the following simple command from the project directory:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ rudy publish
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;There’s huge value in being able to define a routine in one location yet be able to run it from each individual project directory. It establishes a standard process for all of your projects which reduces overhead (including the mental workload) and increases consistency.&lt;/p&gt;

&lt;p&gt;For example, you’ll note the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;publish_github&lt;/code&gt; routine creates a tag called “latest”. That allows me to refer to that tag in long-running or rarely updated documentation when I talk about the most recent release. It’s little things like that that make a big difference over the long run. Both in terms of my time and the visible consistency of a project.&lt;/p&gt;

&lt;h2 id=&quot;future-additions&quot;&gt;Future Additions&lt;/h2&gt;

&lt;p&gt;Astute readers will note a couple glaring improvements than can and should be made to this process. The first is creating the release tag automatically based on the gemspec (or possibly library version). The second is removing the reliance on Rake. There are some tasks that Rake is specifically suited for, but in this case it’s possible to cleanly migrate the calls for building the documentation and Rubygems into Rudy directly.&lt;/p&gt;

&lt;p&gt;And that’s it. Do you automate your release process?&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>A need for virtualized infrastructure tools</title>
   <link href="http://solutious.com/blog/2009/09/10/need-for-tools/"/>
   <updated>2009-09-10T00:00:00+00:00</updated>
   <id>http://solutious.com/blog/2009/09/10/need-for-tools</id>
   <content type="html">&lt;p&gt;Virtualized infrastructure is packed with surprises. There is an interesting post on the &lt;a href=&quot;http://boxedice.com/&quot;&gt;Boxed Ice&lt;/a&gt; blog titled, &lt;a href=&quot;http://blog.boxedice.com/2009/09/08/why-we-moved-away-from-the-cloud-to-a-real-server/&quot;&gt;Why we moved away from “the cloud” to a “real” server&lt;/a&gt;, that highlights two important ones:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;em&gt;Virtualized infrastructure (and Infrastructure as a Service or IaaS specifically) is not a direct replacement for physical hardware.&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Moving to “the cloud” can increase development overhead.&lt;/em&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;not-a-direct-replacement-but-a-new-opportunity-or-three&quot;&gt;Not a direct replacement, but a new opportunity (or three)&lt;/h2&gt;

&lt;p&gt;So if IaaS is not a direct replacement, how are companies using it today? There are currently three primary business cases for using IaaS (unless you’re a startup or otherwise have the luxury of starting new projects from scratch):&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ad-hoc Environments:&lt;/strong&gt; Consider a testing environment that arrives just-in-time and only for the time that you need it. Instead of owning and maintaining physical machines for testing, you or your team can create machines on-the-fly, run your tests, and then shut the machines down. The advantage being you’re in control and you’re also paying only for the time the tests are running. There are also technical advantages in installing and configuring your application from scratch because it can help you find bugs that you wouldn’t find on permanent test machines.&lt;/p&gt;

&lt;p&gt;Another example is rapid-prototyping. If your development or marketing team has an idea, you can spend a few days or a week building a prototype, then launch it on EC2 for internal and external feedback without having to plan and budget for the ongoing costs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Batch Processing:&lt;/strong&gt; Small to medium sized companies now have access to a massive amount of processing power. Before the IaaS model – that is, paying for computing power by the hour – this kind of power was available only large organizations which had the resources to purchase and maintain their own data centres.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pilot projects:&lt;/strong&gt; This one is important for development teams and IT managers in small and medium sized business. You now have the ability to provision your own hardware. While the costs can remain on par (in some cases), you will have more control and be more agile. More importantly you’re developing a knowledge of virtualized infrastructure within your organization. Just like the transition from on-site electricity generators to pay-by-usage utilities, the computing industry is transforming into a new model. You don’t need to move your entire infrastructure to experience this value. All it takes is 1 or 2 machines.&lt;/p&gt;

&lt;p&gt;These examples are just the tip of the iceberg in terms of what’s possible, but they have one important thing in common: &lt;em&gt;these are opportunities that you can employ today with minimal impact to your existing processes.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;development-overhead-a-need-for-tools&quot;&gt;Development overhead, a need for tools&lt;/h2&gt;

&lt;p&gt;Possible? Absolutely. But these opportunities require (sometimes) significant development time to implement. That’s a sign that &lt;em&gt;the ecosystem needs more tools&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Opensource tools:&lt;/strong&gt; Most (if not all) programming languages have opensource libraries that implement the IaaS vendor APIs. But there are very few libraries that provide functionality beyond these core APIs. &lt;a href=&quot;/projects/rudy/&quot;&gt;Rudy&lt;/a&gt; is one example that helps organize complex environments and processes, but there are other approaches. Like &lt;a href=&quot;http://poolpartyrb.com/&quot;&gt;PoolParty&lt;/a&gt; and &lt;a href=&quot;http://libcloud.net/&quot;&gt;libcloud&lt;/a&gt;. This is a good start, &lt;em&gt;but we need more&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Commercial products:&lt;/strong&gt; Products like &lt;a href=&quot;http://rightscale.com/&quot;&gt;RightScale&lt;/a&gt; and &lt;a href=&quot;http://cloudkick.com/&quot;&gt;Cloudkick&lt;/a&gt; which provide web-based interfaces to your virtual infrastructures. And there are companies like &lt;a href=&quot;http://soasta.com/&quot;&gt;SOASTA&lt;/a&gt; and &lt;a href=&quot;http://devver.net/&quot;&gt;Devver&lt;/a&gt; which provide usage-based services on top of IaaS vendors. These tools are great and I’ve had success in training clients how to use them. But again, &lt;em&gt;we need more&lt;/em&gt;.&lt;/p&gt;

&lt;h2 id=&quot;the-road-is-paved-with-experiments&quot;&gt;The road is paved with experiments&lt;/h2&gt;

&lt;p&gt;We need to expand our knowledge of what works and what doesn’t work. So go out and experiment with EC2 or Rackspace or RightScale or Cloudkick. If you’re a development manager, green light a pilot project. If you’re a developer, take a look at a project like &lt;a href=&quot;/projects/rudy/&quot;&gt;Rudy&lt;/a&gt; or &lt;a href=&quot;http://poolpartyrb.com/&quot;&gt;PoolParty&lt;/a&gt; and tear it apart.&lt;/p&gt;

&lt;p&gt;How do we get to a place that’s brimming with mind-blowingly powerful IaaS tools? Practice!&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Restore, Work, Destroy: An EC2 lifecycle</title>
   <link href="http://solutious.com/blog/2009/08/28/restore-work-destroy-ec2-lifecycle/"/>
   <updated>2009-08-28T00:00:00+00:00</updated>
   <id>http://solutious.com/blog/2009/08/28/restore-work-destroy-ec2-lifecycle</id>
   <content type="html">&lt;p&gt;Most of the buzz around virtualized IT infrastructure focuses on dynamic scaling – that is, increasing the number of machines when load is high and decreasing when load is low. There is huge value in being able to do this, but there are other valuable opportunities which get less attention. The opportunity that I am most excited about is &lt;em&gt;temporary infrastructures.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now, temporary infrastructures have  &lt;a href=&quot;http://open.blogs.nytimes.com/2008/05/21/the-new-york-times-archives-amazon-web-services-timesmachine/&quot;&gt;received&lt;/a&gt; &lt;a href=&quot;http://aws.typepad.com/aws/2009/08/pig-latin-high-level-data-processing-with-elastic-mapreduce.html&quot;&gt;some&lt;/a&gt; &lt;a href=&quot;http://selenium-grid.seleniumhq.org/run_the_demo_on_ec2.html&quot;&gt;attention&lt;/a&gt; but the focus is generally limited to variations of batch processing. I’d like to talk about another possibility: launching applications only for the time that you need them.&lt;/p&gt;

&lt;h3 id=&quot;a-just-in-time-issue-tracker&quot;&gt;A Just-in-time Issue Tracker&lt;/h3&gt;

&lt;p&gt;Launching an application, using it, and shutting it down is interesting but it’s hardly mind blowing. I’m going to kick it up a notch by demonstrating how to routinely persist an application and its data between machine instances using &lt;a href=&quot;http://aws.amazon.com/ec2/&quot;&gt;Amazon EC2&lt;/a&gt;, &lt;a href=&quot;http://aws.amazon.com/ebs/&quot;&gt;EBS volumes&lt;/a&gt;, and &lt;a href=&quot;http://solutious.com/projects/rudy/&quot;&gt;Rudy&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Imagine being able to run an issue tracker for your team, only during business hours. Off hours the machine is shut down (along with the applications running on it). Instead of paying $75 / month for the smallest EC2 instance, you’re now paying around $18. And there’s a bonus: you’ll be creating full daily backups as part of your regular process.&lt;/p&gt;

&lt;p&gt;I’m using &lt;a href=&quot;http://www.atlassian.com/software/jira/&quot;&gt;JIRA&lt;/a&gt; for this example because it is a popular bug and issue tracker that’s familiar to many people.&lt;/p&gt;

&lt;h4 id=&quot;what-you-need&quot;&gt;What you need&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;An Amazon Web Services (AWS) account and credentials&lt;/li&gt;
  &lt;li&gt;Some experience running tools on the command-line&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://solutious.com/projects/rudy/getting-started/&quot;&gt;Rudy installed&lt;/a&gt; on your machine&lt;/li&gt;
  &lt;li&gt;A JIRA License (&lt;em&gt;optional&lt;/em&gt;)&lt;/li&gt;
  &lt;li&gt;5 minutes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Note: I am running this demonstration from OS X, but Rudy runs on Windows and Linux as well.&lt;/em&gt;&lt;/p&gt;

&lt;h3 id=&quot;initial-installation&quot;&gt;Initial Installation&lt;/h3&gt;

&lt;p&gt;After installing Rudy, &lt;strong&gt;download the &lt;a href=&quot;http://github.com/rudy/arcade/raw/2009-08-27/ruby/unix/jira.rb&quot;&gt;configuration file&lt;/a&gt;&lt;/strong&gt; for this demonstration. Before running the first command it’s important that you understand what it does:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Launch an instance of Linux in EC2&lt;/li&gt;
  &lt;li&gt;Create a user to run the JIRA application&lt;/li&gt;
  &lt;li&gt;Open port 8080 (for your IP address only)&lt;/li&gt;
  &lt;li&gt;Create a 10GB EBS volume&lt;/li&gt;
  &lt;li&gt;Download, install, and start JIRA&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The meat of the configuration looks like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;before&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:startup&lt;/span&gt;               
  &lt;span class=&quot;n&quot;&gt;adduser&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:jira&lt;/span&gt;                &lt;span class=&quot;c1&quot;&gt;# Create a user on the linux&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;authorize&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:jira&lt;/span&gt;              &lt;span class=&quot;c1&quot;&gt;# machine to run the app.&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;network&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;                   &lt;span class=&quot;c1&quot;&gt;# Open access to port 8080&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;authorize&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8080&lt;/span&gt;             &lt;span class=&quot;c1&quot;&gt;# for your local machine.&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;disks&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;                     &lt;span class=&quot;c1&quot;&gt;# Create an EBS volume where&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;create&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/jira&quot;&lt;/span&gt;             &lt;span class=&quot;c1&quot;&gt;# JIRA will be installed.&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;remote&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:root&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;disable_safe_mode&lt;/span&gt;          &lt;span class=&quot;c1&quot;&gt;# Allow file globs and tildas.&lt;/span&gt;
    
    &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;JIRA is already installed&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;file_exists?&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/jira/app'&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;jira_archive&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;atlassian-jira-standard-3.13.5-standalone.tar.gz&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;uri&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;http://www.atlassian.com/software/jira/downloads/binary&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;wget&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;jira_archive&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;file_exists?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jira_archive&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;cp&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jira_archive&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/jira/jira.tar.gz'&lt;/span&gt; 
    &lt;span class=&quot;n&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/jira'&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/jira/indexes'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/jira/attachments'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/jira/backups'&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;tar&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'jira.tar.gz'&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;mv&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'atlassian-jira-*'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'app'&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;chown&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:R&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'jira'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/jira'&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ls&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:l&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;after&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:start_jira&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h4 id=&quot;when-youre-ready-run-the-following-command&quot;&gt;When you’re ready, run the following command:&lt;/h4&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ rudy --config path/2/jira.rb install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Once this command finishes, you’ll be able to grab the the public DNS for your new EC2 instance by running:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ rudy --config path/2/jira.rb machines
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;jira-setup-optional&quot;&gt;JIRA Setup (optional)&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;This step requires a JIRA license. You can &lt;a href=&quot;http://www.atlassian.com/software/jira/Licenses.jspa&quot;&gt;generate a trial license&lt;/a&gt; or skip to the next section.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Open JIRA in your browser by copying and pasting the public DNS info into the address bar. &lt;strong&gt;Make sure to specify port 8080!&lt;/strong&gt; It should looking something like:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://ec2-75-101-174-156.compute-1.amazonaws.com:8080/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a class=&quot;graphic&quot; href=&quot;/blog/assets/2009-q3/restore-work-destroy-01-setup.png&quot;&gt;&lt;img src=&quot;/blog/assets/2009-q3/restore-work-destroy-01-setup.small.png&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Continue through the setup wizard and you should end up with a page that looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a class=&quot;graphic&quot; href=&quot;/blog/assets/2009-q3/restore-work-destroy-02-installed.png&quot;&gt;&lt;img src=&quot;/blog/assets/2009-q3/restore-work-destroy-02-installed.small.png&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can use JIRA as much as you like. Create a project, file a bug, etc… In the next section we will destroy this instance and later, through the magic of television, restore it back to the state you left it.&lt;/p&gt;

&lt;h3 id=&quot;destroy&quot;&gt;Destroy!&lt;/h3&gt;

&lt;p&gt;This is the exciting part where we destroy the instance and the disk! This next command will:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Stop the JIRA application&lt;/li&gt;
  &lt;li&gt;Create a snapshot of the disk (EBS volume)&lt;/li&gt;
  &lt;li&gt;Destroy the disk (forever)&lt;/li&gt;
  &lt;li&gt;Shutdown the instance (also forever)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The relevant configuration looks like this (note how the destroy routine refers to dependencies for the first two steps):&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;destroy&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;before&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:stop_jira&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:archive&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;disks&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; 
    &lt;span class=&quot;n&quot;&gt;destroy&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/jira&quot;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;after&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:shutdown&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;archive&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;disks&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;archive&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/jira&quot;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h4 id=&quot;take-a-deep-breath-and-run&quot;&gt;Take a deep breath and run:&lt;/h4&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ rudy --config ruby/unix/jira.rb destroy
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The instance is now gone. You can try to reload JIRA in your browser but sadly and perhaps slightly frightening, it’s gone.&lt;/p&gt;

&lt;h3 id=&quot;restore&quot;&gt;Restore&lt;/h3&gt;

&lt;p&gt;And finally the moment we all been waiting for: restoring JIRA to its previous glory. This command will:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Create a new EC2 instance&lt;/li&gt;
  &lt;li&gt;Restore the disk from the most recent backup&lt;/li&gt;
  &lt;li&gt;Start the JIRA application&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is the relevant configuration:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;restore&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;before&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:startup&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;adduser&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:jira&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;authorize&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:jira&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;network&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;                   &lt;span class=&quot;c1&quot;&gt;# Open access to port 8080&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;authorize&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8080&lt;/span&gt;             &lt;span class=&quot;c1&quot;&gt;# for your local machine &lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;                          
  &lt;span class=&quot;n&quot;&gt;disks&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;                     &lt;span class=&quot;c1&quot;&gt;# Create a volume from the&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;restore&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/jira&quot;&lt;/span&gt;            &lt;span class=&quot;c1&quot;&gt;# most recent snapshot&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;after&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:start_jira&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h4 id=&quot;run-the-following-command&quot;&gt;Run the following command:&lt;/h4&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ rudy --config ruby/unix/jira.rb restore
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note that even if you skipped setting up JIRA, it’s in the same state as you left it without having to reinstall in. If you did setup JIRA, you’ll notice that it’s in the same state as you left it too. However, notice how the public DNS is different. That’s because it’s an entirely new machine with an entirely new disk.&lt;/p&gt;

&lt;p&gt;&lt;a class=&quot;graphic&quot; href=&quot;/blog/assets/2009-q3/restore-work-destroy-03-restored.png&quot;&gt;&lt;img src=&quot;/blog/assets/2009-q3/restore-work-destroy-03-restored.small.png&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Don’t forget to destroy the instance again when you’re done!&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&quot;final-thoughts&quot;&gt;Final Thoughts&lt;/h3&gt;

&lt;p&gt;This was a very simple demonstration. What is most interesting to me is that backups are implicitly included in this lifecycle. Not only does it cut the cost of running a machine by over two thirds (assuming business hours), it provides complete daily backups &lt;em&gt;as part of the regular process&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;And of course, if you were to use this configuration, there are other things you’d probably want to do (install MySQL, modify the JIRA configuration, etc…) but it already gives you a look into what is possible with temporary infrastructures.&lt;/p&gt;

&lt;p&gt;What do you think: would this kind of workflow be useful for you?&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Running SSH on Windows</title>
   <link href="http://solutious.com/blog/2009/08/19/ssh-on-windows/"/>
   <updated>2009-08-19T00:00:00+00:00</updated>
   <id>http://solutious.com/blog/2009/08/19/ssh-on-windows</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/Secure_Shell&quot;&gt;SSH&lt;/a&gt; (Secure Shell) is a network protocol that allows data to be exchanged securely between one or more devices. It’s used to automate command execution and transfer files. SSH is most often associated with Linux, Unix, and other “non-Windows” operating systems, but it can run on Windows as well. This document takes you through the steps for installing an SSH server on a Windows machine.&lt;/p&gt;

&lt;h3 id=&quot;overview&quot;&gt;Overview&lt;/h3&gt;

&lt;p&gt;There are &lt;a href=&quot;http://www.openssh.com/windows.html&quot;&gt;several&lt;/a&gt; SSH servers available for Windows, both free and commercial products. I’ve found &lt;a href=&quot;http://www.itefix.no/copssh/&quot;&gt;copSSH&lt;/a&gt; to be the easiest and also the most up to date.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;Download the installation package&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Run installer&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Authorize users&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Copy public key&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Update Security Group (Amazon EC2 only)&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Test connection&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Bundle AMI (Amazon EC2 only)&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Note: This post describes the process for enabling passwordless logins via SSH. You will not be able to login with your regular password.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&quot;download-the-installation-package&quot;&gt;Download the installation package&lt;/h3&gt;

&lt;p&gt;The following installation package must be downloaded to the Windows machine which will run the SSH server.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://sourceforge.net/projects/sereds/files/copSSH/2.1.1/Copssh_2.1.1_Installer.zip/download&quot;&gt;http://sourceforge.net/projects/sereds/files/copSSH/2.1.1/Copssh_2.1.1_Installer.zip/download&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;graphic&quot; src=&quot;/blog/assets/2009-q3/ssh-on-windows-01-extract.png&quot; border=&quot;0&quot; alt=&quot;Right-click the file and select Extract All...&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;run-installer&quot;&gt;Run Installer&lt;/h3&gt;

&lt;p&gt;When you double click the installer, Windows will display a warning because the software isn’t signed by a known publisher. This is typical for free and opensource software on Windows. It’s safe to click Run.&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;graphic&quot; src=&quot;/blog/assets/2009-q3/ssh-on-windows-03-accept.png&quot; border=&quot;0&quot; alt=&quot;It's safe to click Run&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Most of the screens explain themselves, but there is one the requires special attention. You need to specify a user with administrator rights to the machine. This example uses the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Administrator&lt;/code&gt; account, but you can also specify a different one. It will create a new account for you if you specify a user name that does not already exist.&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;graphic&quot; src=&quot;/blog/assets/2009-q3/ssh-on-windows-04-admin.png&quot; border=&quot;0&quot; alt=&quot;Enter a user with administrator privileges&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: Be sure to click Ok when prompted to start copSSH as a service.&lt;/em&gt;&lt;/p&gt;

&lt;h3 id=&quot;authorize-users&quot;&gt;Authorize users&lt;/h3&gt;

&lt;p&gt;After completing the installation, you must authorize SSH access for at least one user. You can do this by going to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Start &amp;gt; All Programs &amp;gt; Copssh &amp;gt; 01. Activate a user&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;graphic&quot; src=&quot;/blog/assets/2009-q3/ssh-on-windows-05-user.png&quot; border=&quot;0&quot; alt=&quot;Start &amp;gt; All Programs &amp;gt; Copssh &amp;gt; 01. Activate a user&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;copy-public-key&quot;&gt;Copy Public Key&lt;/h3&gt;

&lt;p&gt;In order to enable passwordless logins, you must copy your public keys to the Windows machine. You can find your default public keys in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.ssh&lt;/code&gt; but you can specify others as well. Here’s a basic command for creating an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;authorized_keys&lt;/code&gt; file.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ cat ~/.ssh/id_rsa.pub ~/.ssh/id_dsa.pub &amp;gt;&amp;gt; ./authorized_keys
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This file will contain a list of your public keys, one key per line. You must upload this file (or copy and paste the contents) to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C:\Program Files\ICW\home\Administrator\.ssh\authorized_keys&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;graphic&quot; src=&quot;/blog/assets/2009-q3/ssh-on-windows-08-authkeys.png&quot; border=&quot;0&quot; alt=&quot;C:\Program Files\ICW\home\Administrator\.ssh\authorized_keys&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;update-security-group&quot;&gt;Update Security Group&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;For Amazon EC2 customers&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You need to open access to port 22 for the security group associated to your Windows instance. You will need to replace the source IP address used in this example (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;192.168.0.1/32&lt;/code&gt;) with either your &lt;a href=&quot;http://solutious.heroku.com/ip/&quot;&gt;external IP address&lt;/a&gt; (very safe) or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0.0.0.0/32&lt;/code&gt; (less safe because this means it’s open for the entire internet).&lt;/p&gt;

&lt;p&gt;You can use one of the following methods.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Via Rudy&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ rudy-ec2 groups --authorize -p 22 -a 192.168.0.1/32 grp-name
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Via Amazon API Tools&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ ec2-authorize -p 22 -s 192.168.0.1/32 grp-name
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Via Amazon AWS Console&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;graphic&quot; src=&quot;/blog/assets/2009-q3/ssh-on-windows-09-securitygroup.png&quot; border=&quot;0&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;graphic&quot; src=&quot;/blog/assets/2009-q3/ssh-on-windows-10-securitygroup.png&quot; border=&quot;0&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;graphicSubtext&quot;&gt;&lt;a href=&quot;http://console.aws.amazon.com&quot;&gt;console.aws.amazon.com&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h3 id=&quot;test-connection&quot;&gt;Test connection&lt;/h3&gt;

&lt;p&gt;If everything went well, you will be able to login via SSH:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ ssh Administrator@yourwindowsmachine
Last login: Wed Aug 19 07:01:19 2009 from 38.108.74.21

Administrator@yourwindowsmachine
$ 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;bundle-ami&quot;&gt;Bundle AMI&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;For Amazon EC2 customers&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you’re running Windows within EC2, you need to create a machine image based on the running instance. Otherwise you’ll need to follow these steps again when you start a new instance!&lt;/p&gt;

&lt;p&gt;There are two steps to bundling a Windows image. The first creates an image from the running instance and stores it to Amazon S3 (“Simple Storage Service”). Before executing the following command, you’ll want to consider the following:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Have you changed the Administrator password? If not, make sure you’ve written down the password you used to log in the first time. Amazon doesn’t keep it on record so if you don’t know the password, you won’t be able to log in!&lt;/li&gt;
  &lt;li&gt;Make sure everything on the machine is exactly you would like to see it when you start a new instance. For example, if you leave a bunch of files on the desktop that you don’t need, you will have to see them every time you launch a new instance of this image.&lt;/li&gt;
  &lt;li&gt;Empty the recycle bin.&lt;/li&gt;
  &lt;li&gt;Copy anything off of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;D:&lt;/code&gt; drive that you want to keep. That is a temporary disk that is destroyed when the instance is shutdown and not stored in the machine image.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then run the following command to initiate the bundling process.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ ec2-bundle-instance i-12345678 -b BUCKET-IN-US -p IMAGE-NAME -o accessaccessaccess -w secretsecretsecret -K path/2/pk-***.pem -C ~path/2/cert-***.pem --url https://us-east-1.ec2.amazonaws.com --region us-east-1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Bundling can take anywhere from 20 to 60 minutes. You can check on the progress by running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ec2-describe-bundle-tasks&lt;/code&gt;. Once it’s complete, run the following to register the machine image to your account.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ ec2-register --region us-east-1 BUCKET-IN-US/IMAGE-NAME.manifest.xml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That’s it. Don’t forget to shutdown the Windows instance!&lt;/p&gt;

&lt;h3 id=&quot;other-resources&quot;&gt;Other Resources&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.windowsnetworking.com/articles_tutorials/install-SSH-Server-Windows-Server-2008.html&quot;&gt;Installing FreeSSHd&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.teamhackaday.com/2008/04/23/securing-windows-remote-desktop-with-copssh/&quot;&gt;Securing Remote Desktop with copSSH&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have any questions or problems, feel free to contact me via the &lt;a href=&quot;http://groups.google.com/group/rudy-deployment&quot;&gt;discussion group&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Net::SSH 2.0.13 Released</title>
   <link href="http://solutious.com/blog/2009/08/17/net-ssh-2.0.13-released/"/>
   <updated>2009-08-17T00:00:00+00:00</updated>
   <id>http://solutious.com/blog/2009/08/17/net-ssh-2.0.13-released</id>
   <content type="html">&lt;p&gt;I pushed the &lt;a href=&quot;http://github.com/net-ssh/net-ssh/tree/v2.0.13&quot;&gt;2.0.13&lt;/a&gt; maintenance release of &lt;a href=&quot;http://github.com/net-ssh/net-ssh&quot;&gt;Net::SSH&lt;/a&gt; today.&lt;/p&gt;

&lt;h3 id=&quot;notable-fixes&quot;&gt;Notable Fixes&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;arcfour128, arcfour256, and arcfour512 support (&lt;a href=&quot;[http://github.com/net-ssh/net-ssh/issues/closed#issue/4&quot;&gt;GH-4&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;Support for specifying a list of hosts in .ssh/config (&lt;a href=&quot;http://github.com/net-ssh/net-ssh/issues/closed#issue/6&quot;&gt;GH-6&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;Fix for hanging in ServerVersion#negotiate! when using SOCKS5 proxy (&lt;a href=&quot;http://github.com/net-ssh/net-ssh/issues/closed#issue/9&quot;&gt;GH-9&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;known-issues&quot;&gt;Known Issues&lt;/h3&gt;

&lt;p&gt;I could use help with the following bugs:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Doesn’t work with Ruby 1.9 in Windows (&lt;a href=&quot;http://github.com/net-ssh/net-ssh/issues/#issue/5&quot;&gt;GH-5&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;PasswordAuthentication in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssh_config&lt;/code&gt; excludes all other auth methods (&lt;a href=&quot;http://github.com/net-ssh/net-ssh/issues/#issue/8&quot;&gt;GH-8&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;Net:SSH problem with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;open_channel&lt;/code&gt; (&lt;a href=&quot;http://github.com/net-ssh/net-ssh/issues/#issue/1&quot;&gt;GH-1&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;installation&quot;&gt;Installation&lt;/h3&gt;

&lt;p&gt;Via Rubygem, one of:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo gem install net-ssh&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo gem install net-ssh-net-ssh --source http://gems.github.com/&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Via &lt;a href=&quot;http://github.com/net-ssh/net-ssh/tarball/v2.0.13&quot;&gt;.tar.gz&lt;/a&gt; or &lt;a href=&quot;http://github.com/net-ssh/net-ssh/zipball/v2.0.13&quot;&gt;.zip&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;more-info&quot;&gt;More Info&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://github.com/net-ssh/net-ssh&quot;&gt;Codes&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://github.com/net-ssh/net-ssh/issues&quot;&gt;Issues&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://rubyforge.org/projects/net-ssh&quot;&gt;Rubyforge&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://net-ssh.github.com/net-ssh/&quot;&gt;RDocs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;thanks&quot;&gt;Thanks&lt;/h3&gt;

&lt;p&gt;I’d like to send a big thanks to Gerald Talton, ckoehler, Denis Bernard, and Karl Varga for their help.&lt;/p&gt;

&lt;p&gt;This is my first official release as the new maintainer for Net::SSH. Please let know if you find any issues or problems.&lt;/p&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Rudy 0.9 Released</title>
   <link href="http://solutious.com/blog/2009/08/10/rudy-0.9-released/"/>
   <updated>2009-08-10T00:00:00+00:00</updated>
   <id>http://solutious.com/blog/2009/08/10/rudy-0.9-released</id>
   <content type="html">&lt;p&gt;After 8 months of development, testing, writing, and rewriting, Rudy has reached version 0.9. This is an important release because it establishes a baseline for the upcoming 1.0. The configuration syntax, command-line interface, and Ruby APIs are now stable and will not change. The road to 1.0 will be paved with testing, bug fixes, and documentation.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: Rudy 0.9 is not compatible with previous releases. &lt;a href=&quot;http://wiki.github.com/solutious/rudy/upgrading&quot;&gt;See Upgrading&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h3 id=&quot;what-is-rudy&quot;&gt;What is Rudy?&lt;/h3&gt;

&lt;p&gt;Rudy is a development and deployment tool for EC2. It helps you build and maintain infrastructures by organizing them into groups of zones, environments, and roles. By making it quick and easy to build infrastructures, Rudy makes it feasible to run environments only for the time that you need them. &lt;strong&gt;&lt;a href=&quot;http://solutious.com/projects/rudy/getting-started/&quot;&gt;Get started&lt;/a&gt;&lt;/strong&gt; now.&lt;/p&gt;

&lt;h3 id=&quot;who-is-it-useful-for&quot;&gt;Who is it useful for?&lt;/h3&gt;

&lt;p&gt;Rudy is useful to anyone starting a project with Amazon EC2. It’s also useful for launching test environments on-the-fly. My beta customers have been using Rudy to build and maintain their stage and production environments. I even use Rudy to script my release process (I’ll publish my configuration in a future post).&lt;/p&gt;

&lt;p&gt;There are many possibilities. You can find other examples in &lt;a href=&quot;http://github.com/rudy/arcade&quot;&gt;Rudy’s Arcade&lt;/a&gt; and in my &lt;a href=&quot;http://github.com/solutious/ebstest&quot;&gt;EBS test&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;configuration&quot;&gt;Configuration&lt;/h3&gt;

&lt;p&gt;Rudy is configured via several simple domain specific languages. There’s a machines configuration which describes the “physical” properties of your infrastructure and a routines configuration for describing repeatable processes (similar to short scripts).&lt;/p&gt;

&lt;p&gt;The following is an example configuration that creates a machine called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;m-us-east-1b-stage-app-01&lt;/code&gt;. This machine has a 100GB EBS volume mounted at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/rudy/disk1&lt;/code&gt; and one user named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rudy&lt;/code&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;   
 &lt;span class=&quot;n&quot;&gt;machines&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;env&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:stage&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;                   &lt;span class=&quot;c1&quot;&gt;# Define an environment&lt;/span&gt;
     &lt;span class=&quot;n&quot;&gt;ami&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'ami-e348af8a'&lt;/span&gt;            &lt;span class=&quot;c1&quot;&gt;# Specify a machine image&lt;/span&gt;
   
     &lt;span class=&quot;n&quot;&gt;role&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:app&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;                  &lt;span class=&quot;c1&quot;&gt;# Define a role&lt;/span&gt;
       &lt;span class=&quot;n&quot;&gt;disks&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;                    &lt;span class=&quot;c1&quot;&gt;# Define EBS volumes&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/rudy/disk1&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;  
           &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;
           &lt;span class=&quot;n&quot;&gt;device&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/dev/sdr&quot;&lt;/span&gt;
         &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;                       
       &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
     &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

   &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt; 
 &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
 
 &lt;span class=&quot;n&quot;&gt;routines&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
 
   &lt;span class=&quot;n&quot;&gt;startup&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;                      &lt;span class=&quot;c1&quot;&gt;# $ rudy startup&lt;/span&gt;
     &lt;span class=&quot;n&quot;&gt;adduser&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:rudy&lt;/span&gt;       
     &lt;span class=&quot;n&quot;&gt;authorize&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:rudy&lt;/span&gt;               &lt;span class=&quot;c1&quot;&gt;# Enable passwordless login&lt;/span&gt;
                          
     &lt;span class=&quot;n&quot;&gt;disks&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;                   
       &lt;span class=&quot;n&quot;&gt;create&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/rudy/disk1&quot;&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;# Create and mount a volume &lt;/span&gt;
     &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;                       
                         
     &lt;span class=&quot;n&quot;&gt;remote&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:rudy&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;               &lt;span class=&quot;c1&quot;&gt;# Run remote commands via SSH&lt;/span&gt;
       &lt;span class=&quot;n&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;great&quot;&lt;/span&gt;           &lt;span class=&quot;c1&quot;&gt;# $ mkdir -p great&lt;/span&gt;
       &lt;span class=&quot;n&quot;&gt;mysql_init&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:start&lt;/span&gt; 
       &lt;span class=&quot;n&quot;&gt;your_script&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'arg1'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'arg2'&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Call your own scripts&lt;/span&gt;
     &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;                          
   &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
 
 &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;span class=&quot;graphicSubtext&quot;&gt;See the default &lt;a href=&quot;http://github.com/solutious/rudy/raw/master/Rudyfile&quot; title=&quot;A Rudy configuration file&quot;&gt;Rudyfile&lt;/a&gt; for a complete configuration sample&lt;/span&gt;&lt;/p&gt;

&lt;h3 id=&quot;installation&quot;&gt;Installation&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo gem install rudy
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;See &lt;a href=&quot;http://solutious.com/projects/rudy/getting-started/&quot;&gt;Getting Started&lt;/a&gt; for details.&lt;/p&gt;

&lt;h3 id=&quot;more-information&quot;&gt;More Information&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Fork at &lt;a href=&quot;http://github.com/solutious/rudy&quot;&gt;GitHub&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Read the &lt;a href=&quot;http://solutious.com/projects/rudy&quot;&gt;Documentation&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Submit issues to the &lt;a href=&quot;http://github.com/solutious/rudy/issues&quot;&gt;Issue Tracker&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Start a discussion on the &lt;a href=&quot;http://groups.google.com/group/rudy-deployment&quot;&gt;Discussion Group&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Find some &lt;a href=&quot;http://www.youtube.com/watch?v=CgaiIW5Rzes&quot;&gt;Inspiration&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;thanks&quot;&gt;Thanks&lt;/h3&gt;

&lt;p&gt;In addition to everyone that has used and is using Rudy, I’d like to thank (in no specific order):&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Kalin Harvey for the encouragement and answering my random questions.&lt;/li&gt;
  &lt;li&gt;The &lt;a href=&quot;http://rilli.com/&quot;&gt;Rilli&lt;/a&gt; team for the initial usecase and invaluable feedback: Adam Bognar, Andrew Simpson, Caleb Buxton, Colin Brumelle.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://sam.aaron.name&quot;&gt;Sam Aaron&lt;/a&gt; for teaching me about Ruby and communicative programming.&lt;/li&gt;
  &lt;li&gt;Everyone at &lt;a href=&quot;http://groups.google.com/group/utrecht-rb&quot;&gt;Utrecht.rb&lt;/a&gt; for the interest and encouragement.&lt;/li&gt;
  &lt;li&gt;Steve Abatangle for the bug fixes.&lt;/li&gt;
  &lt;li&gt;Mathias Monnerville	for allowing me to register &lt;a href=&quot;http://code.google.com/p/rudy/&quot;&gt;Rudy&lt;/a&gt; at Google Code.&lt;/li&gt;
  &lt;li&gt;Jamis Buck for Net::SSH&lt;/li&gt;
  &lt;li&gt;Glenn Rempe for amazon-ec2 (and the quick releases!)&lt;/li&gt;
  &lt;li&gt;And of course, Keshia Knight Pulliam.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;whats-next&quot;&gt;What’s Next&lt;/h3&gt;

&lt;p&gt;There’s a lot of exciting stuff in store for Rudy and Solutious. Look forward to more announcements in the coming months.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Command-line Twitter with Bash</title>
   <link href="http://solutious.com/blog/2009/07/13/bash-twitter/"/>
   <updated>2009-07-13T00:00:00+00:00</updated>
   <id>http://solutious.com/blog/2009/07/13/bash-twitter</id>
   <content type="html">&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ tweet &quot;The sun is out and I am going to make a sandwich. #montreal #food&quot; &amp;lt;span class=&quot;graphicSubtext&quot;&amp;gt;&amp;lt;a href=&quot;http://twitter.com/solutious/status/2620100947&quot;&amp;gt;Some minutes ago&amp;lt;/a&amp;gt; from web&amp;lt;/span&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I found a &lt;a href=&quot;http://gist.github.com/143067&quot;&gt;gist&lt;/a&gt; the other day by &lt;a href=&quot;http://github.com/defunkt&quot;&gt;defunkt&lt;/a&gt; with a bash function for posting to Twitter from the command-line. It’s a cute hack but it was insecure so I updated it to work securely over HTTPS.&lt;/p&gt;

&lt;h3 id=&quot;step-1-update-bashrc&quot;&gt;Step 1: Update ~/.bashrc&lt;/h3&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;# $ tweet &quot;your message&quot;&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# See: http://solutious.com/blog/2009/07/13/bash-twitter/&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Contributors&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# * @defunkt for the initial version&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# * @anildigital and @grundprinzip for curl-fu&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# * @solutious for the SSL sexytime&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# See: http://curl.netmirror.org/docs/caextract.html&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;CERTS_URI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;http://curl.haxx.se/ca/cacert.pem

&lt;span class=&quot;c&quot;&gt;# SHA1 digest for file: Thu Mar 26 21:23:06 2009 UTC&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# NOTE: This needs to be updated when cacert.pem is updated&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;CERTS_DIGEST&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;331b7e928bd758146ef4a17fee59a63e6ad6b10a

&lt;span class=&quot;c&quot;&gt;# Path to local copy of CA extract &lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;CERTS_FILE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;~/.cacerts.pem

&lt;span class=&quot;k&quot;&gt;function &lt;/span&gt;tweet &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  verifycerts &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return &lt;/span&gt;1
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$*&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
    &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Nothing to tweet!'&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return &lt;/span&gt;1
  &lt;span class=&quot;k&quot;&gt;fi
  &lt;/span&gt;curl &lt;span class=&quot;nt&quot;&gt;--cacert&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$CERTS_FILE&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$*&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; https://twitter.com/statuses/update.xml &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; /dev/null 2&amp;gt;&amp;amp;1
  &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;tweet'd '&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$*&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;'&quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; 

&lt;span class=&quot;c&quot;&gt;# Download extract of CA certs from mozilla.org &lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;function &lt;/span&gt;updatecerts &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  curl &lt;span class=&quot;nv&quot;&gt;$CERTS_URI&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$CERTS_FILE&lt;/span&gt; 2&amp;gt; /dev/null
  verifycerts
  &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Saved to &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$CERTS_FILE&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Make sure the CA certs match the sha1 digest&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;function &lt;/span&gt;verifycerts &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$CERTS_FILE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
    &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$CERTS_FILE&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; does not exist.&quot;&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Try running: updatecerts&quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return &lt;/span&gt;1
  &lt;span class=&quot;k&quot;&gt;fi

  &lt;/span&gt;openssl sha1 &lt;span class=&quot;nv&quot;&gt;$CERTS_FILE&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$CERTS_DIGEST&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; /dev/null
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$?&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; 0 &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
    &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Digest mismatch for &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$CERTS_FILE&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; (maybe it was updated?)&quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return &lt;/span&gt;1
  &lt;span class=&quot;k&quot;&gt;fi
  return &lt;/span&gt;0
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;step-2-update-netrc&quot;&gt;Step 2: Update ~/.netrc&lt;/h3&gt;

&lt;p&gt;Put your twitter credentials into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.netrc&lt;/code&gt;. This file is read by curl.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# put this in ~/.netrc
machine twitter.com
login USERNAME
password PASSWORD
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then update the file permissions so only you can read it:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ chmod 600 ~/.netrc
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;step-3-update-ssl-certs&quot;&gt;Step 3: Update SSL certs&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ source ~/.bashrc
$ updatecerts
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This downloads a copy of the Mozilla SSL &lt;a href=&quot;http://curl.netmirror.org/docs/caextract.html&quot;&gt;certificate authority bundle&lt;/a&gt; to ~/.cacerts.pem. curl uses this file to verify the SSL certificate for http://twitter.com/&lt;/p&gt;

&lt;h3 id=&quot;step-4-tweet&quot;&gt;Step 4: Tweet!&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ tweet &quot;Anything at all&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;errors&quot;&gt;Errors&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Digest mismatch for $CERTS_FILE (maybe it was updated?)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This probably means that the Mozilla SSL &lt;a href=&quot;http://curl.netmirror.org/docs/caextract.html&quot;&gt;certificate authority bundle&lt;/a&gt; has been updated. First check that the date in the &lt;a href=&quot;http://curl.haxx.se/ca/cacert.pem&quot;&gt;bundle&lt;/a&gt; is later than “Thu Mar 26 2009”. If it is, then you need to do the following:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Download the latest copy of the bundle by running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;updatecerts&lt;/code&gt; (ignore the error)&lt;/li&gt;
  &lt;li&gt;Update &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CERTS_DIGEST&lt;/code&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.bashrc&lt;/code&gt; with the output from: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;openssl sha1 $CERTS_FILE&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the date has not changed, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.cacerts.pem&lt;/code&gt; file has been modified. It may have been tampered with or corrupted. Delete it an run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;updatecerts&lt;/code&gt; again.&lt;/p&gt;

&lt;h3 id=&quot;contributors&quot;&gt;Contributors&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://twitter.com/defunkt&quot;&gt;@defunkt&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://twitter.com/anildigital&quot;&gt;@anildigital&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://twitter.com/grundprinzip&quot;&gt;@grundprinzip&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://twitter.com/solutious&quot;&gt;@solutious&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If I missed anyone, please let me know!&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>A new repository for Net::SSH</title>
   <link href="http://solutious.com/blog/2009/06/19/net-ssh-repository/"/>
   <updated>2009-06-19T00:00:00+00:00</updated>
   <id>http://solutious.com/blog/2009/06/19/net-ssh-repository</id>
   <content type="html">&lt;p&gt;I use &lt;a href=&quot;http://net-ssh.rubyforge.org/&quot;&gt;Net::SSH&lt;/a&gt; quite extensively in &lt;a href=&quot;/projects/rudy/&quot;&gt;Rudy&lt;/a&gt; and &lt;a href=&quot;http://github.com/delano/rye/&quot;&gt;Rye&lt;/a&gt; so I was concerned about the future of the project when Jamis Buck &lt;a href=&quot;http://weblog.jamisbuck.org/2009/2/25/net-ssh-capistrano-and-saying-goodbye&quot;&gt;announced his departure&lt;/a&gt; from the project back in February. It’s a great library and without it I would not be able to do this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;script&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:root&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;tar&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:z&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'bonnie64.tar.gz'&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;mv&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'bonnie64'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/tmp/bonnie64'&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/tmp/bonnie64'&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;make&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'SysV'&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;span class=&quot;graphicSubtext&quot;&gt;A configuration snippet from my &lt;a href=&quot;http://github.com/solutious/ebstest/tree/2009-06-19&quot; title=&quot;GitHub: EBS Test respository&quot;&gt;Amazon EBS test&lt;/a&gt; demonstrating Rudy’s shell script style DSL.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;A few weeks ago I ran into a connection problem with Solaris. The issue was related to the encryption modes supported by Net::SSH and was &lt;a href=&quot;http://rubyforge.org/tracker/index.php?func=detail&amp;amp;aid=23742&amp;amp;group_id=274&amp;amp;atid=1123&quot;&gt;first reported&lt;/a&gt; back in January. Luckily a patch was recently posted by Denis Bernard which I reviewed and applied to my local copy. Problem solved.&lt;/p&gt;

&lt;p&gt;Well, my initial problem was solved but not the greater problem of Net::SSH maintenance. I really appreciate the time Jamis has put in to Net::SSH and I want to make sure the library continues to be maintained.&lt;/p&gt;

&lt;h3 id=&quot;a-new-repository&quot;&gt;A New Repository&lt;/h3&gt;

&lt;p&gt;I figured other people could benefit from this patch and there will likely be more patches to come so I &lt;a href=&quot;http://github.com/net-ssh/net-ssh/&quot;&gt;forked the Net:SSH repository&lt;/a&gt; on GitHub with the canonical net-ssh user. I’ve applied the patch mentioned above, updated the test suite, and incremented the version to 2.0.12. I also added a gemspec file so the gem can be distributed via GitHub:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo gem install net-ssh-net-ssh --source=http://gems.github.com/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;an-interim-maintainer&quot;&gt;An Interim Maintainer&lt;/h3&gt;

&lt;p&gt;I have a hunch there are other developers out there who are willing and able to make contributions to the project. My intent is simply to help organize that effort. I plan to apply pull requests and patches but I do not plan to continue feature development myself at this time. For those interested in contributing, I’m happily accepting patches, pull requests, and even suggestions for minor changes. You can email me at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;net-ssh@solutious.com&lt;/code&gt;. If this is successful and/or helpful to the community, I’ll fork over Net::SCP and the rest of the crew as well.&lt;/p&gt;

&lt;p&gt;A final note: I am not a security professional so if anyone has experience in this area and is interested in reviewing changes before they’re pulled into the repo please contact me.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>How to put invite codes on business cards</title>
   <link href="http://solutious.com/blog/2009/05/24/invite-codes-on-business-cards/"/>
   <updated>2009-05-24T00:00:00+00:00</updated>
   <id>http://solutious.com/blog/2009/05/24/invite-codes-on-business-cards</id>
   <content type="html">&lt;p&gt;When I started working on &lt;a href=&quot;/projects/stella/&quot;&gt;Stella&lt;/a&gt; last year, my initial plan was to release it as a for-charge testing service. I figured out a way to put unique invite codes on business cards and about halfway through the project I got them printed and started handing them out to people I met at meetups and other events. It turned out to be a pretty handy way to punctuate a good conversation. The only problem was that about a month before launch I decided to switch gears and release the project as an open source tool. That was a good lesson learned! Don’t give out invite codes until the product is up and running &lt;a href=&quot;#[1]&quot;&gt;[1]&lt;/a&gt;. In any case, I thought I’d share the process I used to create them for anyone else that’s interested in doing something similar.&lt;/p&gt;

&lt;h3 id=&quot;the-process&quot;&gt;The Process&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Generate the invite codes&lt;/li&gt;
  &lt;li&gt;Batch create images&lt;/li&gt;
  &lt;li&gt;Print the cards with &lt;a href=&quot;http://moo.com/&quot;&gt;Moo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;generate-the-invite-codes&quot;&gt;Generate the Invite Codes&lt;/h3&gt;

&lt;p&gt;I wrote a short Ruby script to generate the invite codes in the format &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;in-XXXXXX&lt;/code&gt;. I added the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;in-&lt;/code&gt; to give them a little context and I chose six characters since it’s a good balance between uniqueness (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;31^6 = 887,503,681&lt;/code&gt;) and readability. I also removed the potentially ambiguous characters – i, l, o, 0, and 1 – which also doubles as a handy quick-check for bogus codes. Here’s the script:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;#!/usr/bin/ruby&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Description: Invite code generator&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Usage: ruby genvites [code length] [count]&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# e.g.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# $ ruby genvites 6 3&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# in-5qgczr&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# in-enh4v4&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# in-7jjab1&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;LENGTH&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ARGV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;shift&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_i&lt;/span&gt; 
&lt;span class=&quot;no&quot;&gt;COUNT&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ARGV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;shift&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_i&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# An Array with ambiguous characters removed: i, l, o, 0, 1&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;CHARS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'a'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'z'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'0'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'9'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;flatten&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;%w[i l o 0 1]&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;strand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;CHARS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;rand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;CHARS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;len&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;strand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;COUNT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;times&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; 
  &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;in-&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;LENGTH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;I created an invite codes file with the following commands:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ echo &quot;InviteCode&quot; &amp;gt; invites-2009-05-27.csv
$ ruby geninvites 6 50 &amp;gt;&amp;gt; invites-2009-05-27.csv
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;batch-creates-images&quot;&gt;Batch Creates Images&lt;/h3&gt;

&lt;p&gt;I used Photoshop so that’s the process I describe here but you can use any method that you prefer. You simply need to make 50 images, each with a unique invite code. Other options include &lt;a href=&quot;http://www.gimp.org/&quot;&gt;Gimp&lt;/a&gt;, online image editors like &lt;a href=&quot;http://pixlr.com/&quot;&gt;Pixlr&lt;/a&gt; and &lt;a href=&quot;http://aviary.com/home&quot;&gt;Aviary&lt;/a&gt; or even a Ruby/Perl/Python script.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1:&lt;/strong&gt; Create a CSV file containing the invite codes. The first line of the file should contain the column names. If you’re using the script and commands above then you will have a file with one column named “InviteCode” and 50 codes (Moo has a limit of 50 unique images per batch of business cards). However you choose to generate the file, it should look like this:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;InviteCode
in-92gr41
in-6imab7
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Step 2:&lt;/strong&gt; Create a new image and add a layer with some text in it. The styling of the text will be used for the invite codes. The dimensions of the image depend on the type of card you want to print. For a business card, I used 1040 by 700 at 300 dpi (see this &lt;a href=&quot;http://www.flickr.com/groups/moo/discuss/72157605993507176/&quot;&gt;discussion on Flickr&lt;/a&gt;). Check &lt;a href=&quot;http://us.moo.com/en/help/index.php&quot;&gt;Moo Help&lt;/a&gt; for information on image sizes for all product types. Of course, you’ll also need to style the image however you like (with a background image or colour). Mine looked like this:&lt;/p&gt;

&lt;p&gt;&lt;a class=&quot;graphic&quot; href=&quot;http://farm4.static.flickr.com/3354/3572255315_f828787ed4_o.png&quot;&gt;&lt;img src=&quot;http://farm4.static.flickr.com/3354/3572255315_b97eba8481_m.jpg&quot; alt=&quot;Photoshop: Image Example&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3:&lt;/strong&gt; Add a variable for that layer using &lt;em&gt;Image &amp;gt; Variables &amp;gt; Define&lt;/em&gt;. The name of the variable needs to match the name of the column (i.e. “InviteCode”).&lt;/p&gt;

&lt;p&gt;&lt;a class=&quot;graphic&quot; href=&quot;http://farm4.static.flickr.com/3330/3569725337_f741cac35f_o.png&quot;&gt;&lt;img src=&quot;http://farm4.static.flickr.com/3330/3569725337_85832200e2_m.jpg&quot; alt=&quot;Photoshop -&amp;gt; Image -&amp;gt; Variables -&amp;gt; Define&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;
&lt;br /&gt;
&lt;a class=&quot;graphic&quot; href=&quot;http://farm4.static.flickr.com/3613/3569725403_7bc9330090_o.png&quot;&gt;&lt;img src=&quot;http://farm4.static.flickr.com/3613/3569725403_1436288125_m.jpg&quot; alt=&quot;Photoshop: Define Variables&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4:&lt;/strong&gt; Import the CSV file from &lt;em&gt;Image &amp;gt; Variables &amp;gt; Data Sets&lt;/em&gt; or click “Next” in the &lt;em&gt;Define&lt;/em&gt; screen. Click the “Import…” button and make sure the two checkboxes are checked (“Use first column” and “Replace existing datasets”).&lt;/p&gt;

&lt;p&gt;&lt;a class=&quot;graphic&quot; href=&quot;http://farm4.static.flickr.com/3649/3569725463_922facf613_o.png&quot;&gt;&lt;img src=&quot;http://farm4.static.flickr.com/3649/3569725463_7e6dd9e25e_m.jpg&quot; alt=&quot;Photoshop: Import Data&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 5:&lt;/strong&gt; Generate the unique PSD files with &lt;em&gt;File &amp;gt; Export &amp;gt; Data Sets as Files&lt;/em&gt;. The default settings will name the files in the format “original-name_invitecode.psd”.&lt;/p&gt;

&lt;p&gt;&lt;a class=&quot;graphic&quot; href=&quot;http://farm4.static.flickr.com/3323/3569725537_c2706cee5e_o.png&quot;&gt;&lt;img src=&quot;http://farm4.static.flickr.com/3323/3569725537_cc920f2fc3_m.jpg&quot; alt=&quot;Photoshop: Export Files&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 6:&lt;/strong&gt; Convert the PSD files to JPG with &lt;em&gt;File &amp;gt; Scripts &amp;gt; Image Processor&lt;/em&gt;. Select the input folder containing the PSD files, JPG encoding, and the quality.&lt;/p&gt;

&lt;p&gt;&lt;a class=&quot;graphic&quot; href=&quot;http://farm4.static.flickr.com/3593/3569852523_955101ee51_o.png&quot;&gt;&lt;img src=&quot;http://farm4.static.flickr.com/3593/3569852523_1e6a33da4b_m.jpg&quot; border=&quot;0&quot; alt=&quot;Photoshop: Convert PSD to JPG&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;take-it-to-the-printers&quot;&gt;Take it to the printers&lt;/h3&gt;

&lt;p&gt;It’s now time to &lt;a href=&quot;http://www.moo.com/en/projects/&quot;&gt;start the printing process&lt;/a&gt; with Moo &lt;a href=&quot;#[2]&quot;&gt;[2]&lt;/a&gt;. Their interface is pretty self-explanatory so I’ll only mention a few things here.&lt;/p&gt;

&lt;p&gt;If you’re going with business cards, they have two batch sizes: 50 and 200. Obviously it’s cheaper per card to get 200, but they have a limit of 50 unique images (i.e. invite codes) so you’ll end up with duplicates (the other card types, like the mini cards allow up to 100 unique images).&lt;/p&gt;

&lt;p&gt;They have several ways to upload photos, including via Flickr. I chose to go the manual route and upload all 50 photos to Moo. My guess is it’s probably easier to use a Flickr upload tool, but I haven’t tried it. After you’ve uploaded the photos, you’ll be asked to “Add Text”. You can enter your business name and contact info here using one of their preset templates or you can upload another image to use instead. If you’re uploading an image, you’ll need to use the full landscape template as shown here:&lt;/p&gt;

&lt;p&gt;&lt;a class=&quot;graphic&quot; href=&quot;http://farm3.static.flickr.com/2425/3570537526_3e6a29dbd4_o.png&quot;&gt;&lt;img src=&quot;http://farm3.static.flickr.com/2425/3570537526_32d0fd2f85_m.jpg&quot; border=&quot;0&quot; alt=&quot;Moo: Select Template&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The only remaining choice is the type of paper: “Green” or “Classic”. A few observations: the 100% recycled paper is chlorine free and has a flat, matte finish. The classic is “elemental chlorine free” and is a bit shiny and fancier looking. I don’t understand the environmental implications of either choice so if I don’t consider the environment, I’d choose the classic. If the recycled paper does offer an environmental benefit I’d go with that. It’s not that the green is unattractive it’s just that the classic is more attractive.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;And that’s how I put unique invite codes on business cards. It’s a bit of work, but it’s cheap and it gives people a reason to keep your card. Just make sure you launch the product!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update: Improved ruby code example with feedback from &lt;a href=&quot;http://twitter.com/narnach&quot;&gt;Wes&lt;/a&gt; and &lt;a href=&quot;http://twitter.com/FiXato&quot;&gt;Filip&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&quot;notes&quot;&gt;Notes&lt;/h3&gt;

&lt;p&gt;&lt;a name=&quot;[1]&quot;&gt;&amp;nbsp;&lt;/a&gt; [1] I kept track of the codes that I gave out so they'll still work when we do release a product. It's kind of annoying to keep a business card around for an indefinite period of time so if you have one (or had one) just send me an email whenever the time comes and we'll figure it out.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;[2]&quot;&gt;&amp;nbsp;&lt;/a&gt; [2] I recommend Moo because I don't know of any other printer that can produce business cards with unique images for $21.99 (USD). If there are others, let me know!&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>A Fine Brand: from ascii to awesome in 8 sweet months</title>
   <link href="http://solutious.com/blog/2009/05/15/a-fine-brand/"/>
   <updated>2009-05-15T00:00:00+00:00</updated>
   <id>http://solutious.com/blog/2009/05/15/a-fine-brand</id>
   <content type="html">&lt;p&gt;The new version of &lt;a href=&quot;http://solutious.com/&quot;&gt;Solutious.com&lt;/a&gt; went live this week as part of a larger effort to develop a brand for the company and the products I’m working on. I’ve been working with designers &lt;a href=&quot;http://www.adambognar.com/&quot;&gt;Adam Bognar&lt;/a&gt; and &lt;a href=&quot;http://andrewsimpsondesign.com/&quot;&gt;Andrew Simpson&lt;/a&gt; and I’m really excited about how it turned out. I thought it would be interesting to take a look at how the site and brand developed over the past 8 months.&lt;/p&gt;

&lt;h3 id=&quot;prehistory&quot;&gt;Prehistory&lt;/h3&gt;

&lt;p&gt;When I started the company in 2006, I put up what I thought would be a temporary homepage. I had an ongoing contract with a great company so I didn’t have an immediate need to update the site. Looking back, I probably had too many eggs in that one basket. It worked out okay, but the prudent choice would have been to spend a little time on business development regardless of the circumstances. In any case, the only information on the site for 2 years was the name of the company and a phone number.&lt;/p&gt;

&lt;p&gt;&lt;a class=&quot;graphic&quot; href=&quot;http://farm4.static.flickr.com/3014/3531968415_c1716cef10.jpg&quot;&gt;&lt;img src=&quot;http://farm4.static.flickr.com/3014/3531968415_c1716cef10_m.jpg&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;october-2008-a-rudimentary-start&quot;&gt;October 2008, a rudimentary start&lt;/h3&gt;

&lt;p&gt;In 2008 I decided to shift the focus of the company from providing services to bootstrapping a product (more about that in a future post). I absolutely needed a website at this point and after a few months of intense research and prototyping I came up with this:&lt;/p&gt;

&lt;p&gt;&lt;a class=&quot;graphic&quot; href=&quot;http://farm3.static.flickr.com/2466/3532525486_e41a1930e2_o.png&quot;&gt;&lt;img src=&quot;http://farm3.static.flickr.com/2466/3532525486_dca088dbdd_m.jpg&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I was still heavy into product development so I had no content. There were no slogans and there was only a factual description of the company. I needed to put &lt;em&gt;something&lt;/em&gt; on the homepage so I threw in a motivational Samuel Johnson[1] quote: &lt;em&gt;“All industry must be excited by hope”&lt;/em&gt;. I hadn’t put much thought into it at the time, I simply thought it was interesting given the sombre tone of the economy, but as it turned out the spirit of that quote became the first kernel of the Solutious brand.&lt;/p&gt;

&lt;p&gt;However, to say this design was an improvement over the stark yet earnest ASCII is a tough sell. It was more like a cry for help. I clearly required the services of a professional.&lt;/p&gt;

&lt;h3 id=&quot;january-2009-the-quick-fix&quot;&gt;January 2009, the quick fix&lt;/h3&gt;

&lt;p&gt;That professional came in the form of &lt;a href=&quot;http://andrewsimpsondesign.com/&quot;&gt;Andrew Simpson&lt;/a&gt;. I hadn’t worked with Andrew before but we’d been friends for a while and I was impressed by his &lt;a href=&quot;http://andrewsimpsondesign.com/web/&quot;&gt;previous work&lt;/a&gt;. He was (and still is) incredibly busy as one of the founders of &lt;a href=&quot;http://rilli.com/&quot;&gt;Rilli&lt;/a&gt; so I was fortunate to get some of his time.&lt;/p&gt;

&lt;p&gt;I had a simple, two-pronged request: a quick fix and a plan for the future. I still had very little content for him to work with (and for some reason I decided to use a silly quote from Alistair Cockburn), so I was quite pleased with what he came back with.&lt;/p&gt;

&lt;p&gt;&lt;a class=&quot;graphic&quot; href=&quot;http://farm3.static.flickr.com/2448/3531715509_e8df15a3fc_o.png&quot;&gt;&lt;img src=&quot;http://farm3.static.flickr.com/2448/3531715509_954b63053e_m.jpg&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I released the first public version of &lt;a href=&quot;http://solutious.com/projects/stella/&quot;&gt;Stella&lt;/a&gt; around the same time and shortly after this design went up I began working on &lt;a href=&quot;http://solutious.com/projects/rudy/&quot;&gt;Rudy&lt;/a&gt;. You’ll notice the title on this homepage is “The Performance Testing Company”. That’s because my original focus was performance testing tools (I’ll talk more about the business side of things in that upcoming post). With the introduction of Rudy, a development and deployment tool, I removed the word “testing” and adjusted my approach to include the notion of human performance. Software shouldn’t just perform well at run-time, it also needs to perform well at development time.&lt;/p&gt;

&lt;h3 id=&quot;march-2009-the-prototype&quot;&gt;March 2009, the prototype&lt;/h3&gt;

&lt;p&gt;The project really started to take shape in March. I had a much better understanding of both the products and the direction of the company so when Andrew brought &lt;a href=&quot;http://www.adambognar.com/&quot;&gt;Adam Bognar&lt;/a&gt; on board there was a lot more content to work with. Adam has a tonne of &lt;a href=&quot;http://www.adambognar.com/brand/&quot;&gt;branding experience&lt;/a&gt; so I was excited to have him involved.&lt;/p&gt;

&lt;p&gt;We had a couple conversations over Skype and I sent them a motley collection of copy (“Developing web applications in today’s world is no easy task”), old-timey advertising slogans (“&lt;a href=&quot;http://www.hyperkitten.com/pics/tools/ads/kk2.jpg&quot;&gt;Good Natured Tools&lt;/a&gt;”, “&lt;a href=&quot;http://www.flickr.com/photos/joan_thewlis/2623269403/in/set-72157605179833653/&quot;&gt;World Famous Components&lt;/a&gt;”) and examples of &lt;a href=&quot;http://www.flickr.com/groups/earlyadvertising/pool/&quot;&gt;early advertising&lt;/a&gt;. I even sleuthed out a turn of the (19th) century &lt;a href=&quot;/media/solutious-theme-barrel-house-annie.mp3&quot;&gt;theme song&lt;/a&gt;. Shortly after they created and built the prototype.&lt;/p&gt;

&lt;p&gt;&lt;a class=&quot;graphic&quot; href=&quot;http://farm4.static.flickr.com/3391/3532525628_8c734f7ff6_o.png&quot;&gt;&lt;img src=&quot;http://farm4.static.flickr.com/3391/3532525628_0c81e2a967_m.jpg&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I was pretty stoked at this point. We had the content, we had logos, and for the first time in this process we had some focus. I was envisioning a future for Solutious based on this design. But they weren’t done.&lt;/p&gt;

&lt;h3 id=&quot;may-2009-a-fine-brand&quot;&gt;May 2009, A Fine Brand&lt;/h3&gt;

&lt;p&gt;About a month or so after we went live with the prototype, Adam sent me this:&lt;/p&gt;

&lt;p&gt;&lt;a class=&quot;graphic&quot; href=&quot;http://farm3.static.flickr.com/2288/3532525830_9611b7ece5_o.png&quot;&gt;&lt;img src=&quot;http://farm3.static.flickr.com/2288/3532525830_ec2dfdedab.jpg?v=1242357903&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I was blown away. This design says everything I want people to know about Solutious. On top of that, there’s a wealth of visual components that allows for all manner of flexible and dynamic content. This blog for example fits in perfectly and I’ll be able to bring in the product documentation too. Andrew suggested using &lt;a href=&quot;http://wiki.novemberborn.net/sifr3/&quot;&gt;sIFR&lt;/a&gt; to render the text components. I didn’t fully understand the value until I started looking at the templates myself. If I want to change a slogan, create a new title, etc… I can make those changes on the fly. The intermediary step of creating and uploading an image is gone. Once the dust settles I may convert some static components to images, but at this stage that flexibility to make changes is extremely valuable.&lt;/p&gt;

&lt;h3 id=&quot;on-branding&quot;&gt;On Branding&lt;/h3&gt;

&lt;p&gt;Branding and brand development have a bad rap outside of design and business circles. Brands tend to be viewed as a mere interpretation, often a false one, of what a company or product actually is or does. That’s fair because there are a lot of dubious and/or misleading brands (&lt;a href=&quot;http://www.fernandes-softdrinks.com/&quot;&gt;Fernandez&lt;/a&gt;, I’m looking at to you), but it’s not the only interpretation. It’s also possible and even advantageous to align a brand with reality. This is particularly valuable for small companies and micro-ISVs because it’s a way to align one’s personal and professional goals.&lt;/p&gt;

&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;I can’t give enough credit to Adam and Andrew for creating this honest and cohesive brand from my haphazard reference material[2]. I wasn’t sure what to expect when we started out. I certainly had no idea that the end result would be something that motivated me to bring the company to the next level. I hope they got as much value out of the process as much as I did!&lt;/p&gt;

&lt;p&gt;It was a fun, non-linear, and surprising project. If I’ve ever been excited about and hopeful for the future, it’s now.&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;notes&quot;&gt;Notes&lt;/h3&gt;

&lt;p&gt;[1] I ran a tiny, underground &lt;a href=&quot;http://goldensword.ca/t-shirts/&quot;&gt;t-shirt&lt;/a&gt; business in 2006-2007. By “tiny” I’m referring to the fact that I had only one design and by “underground” I mean to say that the only sales channel was me wearing it and random strangers stopping me to ask about it. The shirt was a drawing of Louis Riel (Canada’s preeminent historical rebel) but when I was in the United States I’d say it was Edgar Allen Poe. I had several other designs in the pipeline, including one of &lt;a href=&quot;http://en.wikipedia.org/wiki/Samuel_Johnson&quot;&gt;Samuel Johnson&lt;/a&gt; (who wrote the first english dictionary by the way). It was going to be a drawing of him smiling while &lt;a href=&quot;http://www.1902encyclopedia.com/J/JOH/samuel-johnson-reynolds.jpg&quot;&gt;reading the newspaper&lt;/a&gt; with text below that read, “Samuel L Johnson”. If you’re into t-shirts and you’re in Montréal, I highly recommend &lt;a href=&quot;http://www.portezblank.com/&quot;&gt;Blank&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;[2] I did make one contribution to the design – a sketch of the Stella logo. Fortunately the end result looks much less like two whales kissing.&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;graphic&quot; src=&quot;http://farm4.static.flickr.com/3638/3532844239_56b44c631a_s.jpg&quot; /&gt;&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>What GitHub's Punch Cards Say</title>
   <link href="http://solutious.com/blog/2009/05/06/github-punchcards/"/>
   <updated>2009-05-06T00:00:00+00:00</updated>
   <id>http://solutious.com/blog/2009/05/06/github-punchcards</id>
   <content type="html">&lt;p&gt;I’m fascinated with GitHub’s &lt;a href=&quot;http://github.com/why/shoes/graphs/punch_card&quot;&gt;punch&lt;/a&gt; &lt;a href=&quot;http://github.com/mislav/hanna/graphs/punch_card&quot;&gt;cards&lt;/a&gt;. They’re visual representations of project commits by day and hour and they’re available for every public project on GitHub. Here’s the punch card for &lt;a href=&quot;http://github.com/mislav/will_paginate/&quot;&gt;mislav-will_paginate&lt;/a&gt;, one of the &lt;a href=&quot;http://github.com/popular/watched&quot;&gt;most popular projects&lt;/a&gt; on GitHub:&lt;/p&gt;

&lt;h3 id=&quot;will_paginate&quot;&gt;will_paginate&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;http://github.com/mislav/will_paginate/graphs/punch_card&quot;&gt;&lt;img src=&quot;http://farm4.static.flickr.com/3382/3507637336_e1b9c97b20_o.png&quot; border=&quot;0&quot; width=&quot;400&quot; height=&quot;150&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The punch card says &lt;a href=&quot;http://github.com/mislav/&quot;&gt;Mislav&lt;/a&gt; works hard! He committed at all hours of the day, every day of the week (the larger the dot, the greater number of commits). It’s important to note, when looking at the punch cards, how many active developers have committed to the project. You could look through the &lt;a href=&quot;http://github.com/mislav/will_paginate/commits&quot;&gt;list of commits&lt;/a&gt; but that’s tedious and verbose. The quickest way to gauge how many active developers there are on a project is to look at the &lt;a href=&quot;http://github.com/mislav/will_paginate/graphs/impact&quot;&gt;impact graph&lt;/a&gt; (note that there are several committers for will_paginate, but the vast majority are from two accounts, both of which are Mislav).&lt;/p&gt;

&lt;h2 id=&quot;punch-cards-over-time&quot;&gt;Punch Cards Over Time&lt;/h2&gt;

&lt;p&gt;I thought it would be interesting to see what a punch card looked like over time. I started saving them for a few of my own projects so I could animate them.&lt;/p&gt;

&lt;h3 id=&quot;rye-031-to-064&quot;&gt;Rye (0.3.1 to 0.6.4)&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;http://github.com/delano/rye&quot;&gt;Rye&lt;/a&gt; is a small project that I started on April 4th for executing SSH commands from Ruby. I wrote the core of it over a couple of weekends and then iterated over the following few weeks. You can see that in the animation below.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://github.com/delano/rye/graphs/punch_card&quot;&gt;&lt;img src=&quot;http://farm4.static.flickr.com/3605/3506751765_24443ccb39_o.gif&quot; border=&quot;0&quot; width=&quot;400&quot; height=&quot;150&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;rudy-040-to-073&quot;&gt;Rudy (0.4.0 to 0.7.3)&lt;/h3&gt;

&lt;p&gt;I also saved them for a much larger project, &lt;a href=&quot;http://github.com/solutious/rudy&quot;&gt;Rudy&lt;/a&gt;. I started Rudy in February while doing some deployment work for &lt;a href=&quot;http://rilli.com/&quot;&gt;Rilli&lt;/a&gt;. The first frame is from version 0.4 and the second frame is version 0.5. They’re so different that it would be easy to assume I made a mistake generating the animation. That difference represents a month of hard work where I wrote and re-wrote the project several times.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://github.com/solutious/rudy/graphs/punch_card&quot;&gt;&lt;img src=&quot;http://farm4.static.flickr.com/3359/3506751705_89f1fb5e38_o.gif&quot; border=&quot;0&quot; width=&quot;400&quot; height=&quot;150&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h2 id=&quot;in-conclusion&quot;&gt;In Conclusion&lt;/h2&gt;

&lt;p&gt;What I love about the punch cards is that they’re both informative and motivational. They give me a better understanding of how I work and how my effort relates to that of other open source developers. When I’m focused on a goal like getting the next version out the door, I occasionally forget what I went through to get there. The punch cards help me remember.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Louise Hendy Day, a Celebration of Realtime Marketing</title>
   <link href="http://solutious.com/blog/2009/05/05/louise-hendy-day/"/>
   <updated>2009-05-05T00:00:00+00:00</updated>
   <id>http://solutious.com/blog/2009/05/05/louise-hendy-day</id>
   <content type="html">&lt;p&gt;If you’re like &lt;a href=&quot;http://twitter.com/solutious&quot;&gt;me&lt;/a&gt;, you woke up today thinking May 5th was Cinco de Mayo. What people like us didn’t know is that it’s also Louise Hendy Day. This is probably the first and last time you’ll hear about Louise Hendy Day, but the implications of it are pretty interesting.&lt;/p&gt;

&lt;p style=&quot;text-align: center&quot;&gt;&lt;a href=&quot;http://twitter.com/#search?q=louisehendyday&quot; style=&quot;text-decoration: none;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://farm4.static.flickr.com/3569/3505434648_36eca44c11.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;a-fictitious-holiday&quot;&gt;A Fictitious Holiday&lt;/h3&gt;

&lt;p&gt;Louise Hendy Day is a fictitious holiday created by a &lt;a href=&quot;https://twitter.com/louise_hendy&quot;&gt;single person&lt;/a&gt;, earlier today, in an attempt to get into the trending topics on Twitter. And it worked. At least for a few hours (it’s no longer a trending topic as of 16:00 EST but the &lt;a href=&quot;http://search.twitter.com/search?q=%23louisehendyday&quot;&gt;flurry of messages continues&lt;/a&gt;).&lt;/p&gt;

&lt;p style=&quot;text-align: center&quot;&gt;&lt;a href=&quot;http://tweetstats.com/trends&quot; style=&quot;text-decoration: none;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://farm4.static.flickr.com/3357/3504801219_27d736ccf8.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Why is this important? It’s important because we’ve heard a lot about the power of the web, “social media” in particular, to reach out to build and maintain networks of clients and customers. Rarely however, do we see this power in action, &lt;em&gt;in real time&lt;/em&gt;. One person generated a massive buzz literally out of nothing. The product is a faux-celebration for a holiday that doesn’t otherwise exist.&lt;/p&gt;

&lt;h3 id=&quot;a-new-way-to-do-business&quot;&gt;A New Way to Do Business&lt;/h3&gt;

&lt;p&gt;Now, there are two ways you can view Louise Hendy Day: a useless, passing fad or &lt;em&gt;a completely new way to do business&lt;/em&gt;. You can communicate with current and prospective customers in real-time. It’s like having a conversation with thousands of people at the same time.&lt;/p&gt;

&lt;p&gt;Twitter won’t do this alone – there will be other service providers – but already today, right now we have a tool more powerful than any PR agency ever had. That’s pretty exciting.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Goodnight Sweet Prince (Dreamhost)</title>
   <link href="http://solutious.com/blog/2009/05/03/goodnight-sweet-prince-dreamhost/"/>
   <updated>2009-05-03T00:00:00+00:00</updated>
   <id>http://solutious.com/blog/2009/05/03/goodnight-sweet-prince-dreamhost</id>
   <content type="html">&lt;p&gt;I had a difficult time putting to words the excitement I felt when GitHub announced &lt;a href=&quot;http://github.com/blog/315-cname-support-for-github-pages&quot;&gt;CNAME support&lt;/a&gt;. And now, just a few short months later I’ve finally freed myself from Dreamhost’s shackles. I’m now using GitHub for all my hosting needs (including solutious.com) and I must say, it feels pretty good.&lt;/p&gt;

&lt;p&gt;Shared hosting has served a useful purpose over the years, but it’s days are numbered. &lt;a href=&quot;http://heroku.com/pricing&quot;&gt;Heroku&lt;/a&gt;: free. &lt;a href=&quot;http://code.google.com/appengine/&quot;&gt;Google App Engine&lt;/a&gt;: free. &lt;a href=&quot;http://appjet.com/&quot;&gt;AppJet&lt;/a&gt;: free. You can’t argue with that. GitHub is not free but CNAME support is included with all paid accounts which I already have. I’m now riding the workflow of the future!&lt;/p&gt;

&lt;h2 id=&quot;workflow-of-the-future&quot;&gt;Workflow of the Future&lt;/h2&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Me -&amp;gt; TextMate -&amp;gt; Markdown -&amp;gt; Terminal -&amp;gt; Jekyll -&amp;gt; Git -&amp;gt; You
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

</content>
 </entry>
 
 <entry>
   <title>It's an outrake!</title>
   <link href="http://solutious.com/blog/2009/04/30/its-an-outrake/"/>
   <updated>2009-04-30T00:00:00+00:00</updated>
   <id>http://solutious.com/blog/2009/04/30/its-an-outrake</id>
   <content type="html">&lt;p&gt;This is a story about Ruby mixins, Rake, and hell. After releasing &lt;a href=&quot;http://github.com/solutious/rudy&quot; title=&quot;Rudy: not your grandparents' deployment tool&quot;&gt;Rudy&lt;/a&gt; 0.6 last week, I started immediately on 0.7. This next version has a rebuilt DSL for the routines configuration, including a new syntax for running shell commands. The new syntax makes it possible to specify shell commands like methods. You can probably see where this is heading. First, a comparison of the old and new syntax:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Old, 0.6 syntax&lt;/strong&gt;&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;routines&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;startup&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;after&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:root&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;mkdir -p /path/2/create&quot;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;strong&gt;New, 0.7 syntax&lt;/strong&gt;&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;routines&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;startup&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;after&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:root&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/path/2/create&quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;There are several advantages to using the new syntax which I’ll cover in a future post. Right now, I’ll cut to the hellish chase.&lt;/p&gt;

&lt;p&gt;Both DSLs produce a configuration hash. Nothing else should happen when they’re parsed. And nothing else did happen until I tried running the tests with rake. The old syntax was fine, but I was getting some strange errors with the new syntax. Stuff like&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Error in test/10_config/30_machines_test.rb: can't convert Fixnum into String
/usr/local/lib/ruby/1.9.1/fileutils.rb:1386:in `path'
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;FileUtils? That’s weird, I don’t use FileUtils. Or do I?&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rake-0.8.4/lib/rake.rb&lt;/code&gt; includes &lt;a href=&quot;http://www.ruby-doc.org/core/classes/FileUtils.html&quot;&gt;FileUtils&lt;/a&gt; into the RakeFileUtils module and later includes RakeFileUtils &lt;em&gt;into the global namespace&lt;/em&gt;. My criminy!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Offensive ruby code&lt;/strong&gt;&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;RakeFileUtils&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;FileUtils&lt;/span&gt;       &lt;span class=&quot;c1&quot;&gt;# Nothing wrong here&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# ... later on&lt;/span&gt;
&lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RakeFileUtils&lt;/span&gt;     &lt;span class=&quot;c1&quot;&gt;# Noooooooo&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;That means when I’m running rake the following methods are accessible from everywhere: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cd&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mkdir&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;touch&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rm&lt;/code&gt;, …! The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mkdir&lt;/code&gt; in the DSL was &lt;em&gt;being executed as it was parsed&lt;/em&gt;. That’s insane. Thank the Great Scott I wasn’t testing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rm&lt;/code&gt;.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Rudy, A Replacement for EC2 API Tools.</title>
   <link href="http://solutious.com/blog/2009/04/22/rudy-ec2-api-tools-replacement/"/>
   <updated>2009-04-22T00:00:00+00:00</updated>
   <id>http://solutious.com/blog/2009/04/22/rudy-ec2-api-tools-replacement</id>
   <content type="html">&lt;p&gt;&lt;em&gt;NOTE: This post is historically accurate but out of date. See: &lt;a href=&quot;/blog/2009/08/10/rudy-0.9-released/&quot;&gt;Rudy 0.9 Released&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Rudy is a &lt;a href=&quot;/2009/04/21/rudy-deployment-introduction/&quot;&gt;development and deployment tool&lt;/a&gt; for EC2. It comes with an executable called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rudy-ec2&lt;/code&gt; that can also be used as a replacement for Amazon’s EC2 API tools. The EC2 API tools are a great reference implementation but they’re unfriendly and become unwieldily when you have more than a few instances. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rudy-ec2&lt;/code&gt; is an alternative to these tools that can be used on it’s own (you don’t need to start using Rudy), allowing you to incorporate Rudy into your development process gradually.&lt;/p&gt;

&lt;h2 id=&quot;installation&quot;&gt;Installation&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rudy-ec2&lt;/code&gt; is included with Rudy so if you’ve already installed Rudy, you can skip to the next section.&lt;/p&gt;

&lt;p&gt;Download Rudy from &lt;a href=&quot;http://github.com/solutious/rudy&quot;&gt;github.com&lt;/a&gt; or install it via RubyGems:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo gem install rudy
$ sudo gem install solutious-rudy --source http://gems.github.com/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;NOTE: If you are not installing via RubyGems and running Ruby 1.8.x, you need to make sure the Ruby dependencies (see the &lt;a href=&quot;http://github.com/solutious/rudy/blob/master/README.rdoc&quot;&gt;README&lt;/a&gt;) are installed and in your LOAD_PATH. Ryan Tomayko wrote &lt;a href=&quot;http://gist.github.com/54177&quot;&gt;a gist&lt;/a&gt; about it.&lt;/p&gt;

&lt;h2 id=&quot;configuration-3-ways-to-do-it&quot;&gt;Configuration, 3 ways to do it&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rudy-ec2&lt;/code&gt; needs your Amazon Web Services credentials in order to execute commands on EC2. You can configure these in 3 ways: rudy configuration, environment variables or command-line options.&lt;/p&gt;

&lt;h3 id=&quot;rudy-configuration-method-1&quot;&gt;Rudy Configuration (method 1)&lt;/h3&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rudy-ec2&lt;/code&gt; can use the same configuration as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rudy&lt;/code&gt;. If you’ve already created a Rudy configuration file, you don’t need to do anything else. Otherwise, run the following commands:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ rudy generate-config
  [edit ~/.rudy/config with your Amazon Web Services credentials] 
$ rudy init
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;NOTE: &lt;em&gt;The above command is &lt;strong&gt;rudy&lt;/strong&gt; and not &lt;strong&gt;rudy-ec2&lt;/strong&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h3 id=&quot;environment-variables-method-2&quot;&gt;Environment Variables (method 2)&lt;/h3&gt;

&lt;h4 id=&quot;bash&quot;&gt;Bash&lt;/h4&gt;
&lt;p&gt;Add the following to your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.bashrc&lt;/code&gt; file:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;AWS_ACCESS_KEY='your_aws_key'
AWS_SECRET_KEY='your_aws_secret'
AWS_ACCOUNT_NUMBER=123456789012
export AWS_ACCESS_KEY AWS_SECRET_KEY AWS_ACCOUNT_NUMBER

EC2_CERT=path/2/cert.pem
EC2_PRIVATE_KEY=path/2/pk.pem
export EC2_CERT EC2_PRIVATE_KEY
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then either start working in a new terminal window or run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;source ~/.bashrc&lt;/code&gt; to refresh your current one.&lt;/p&gt;

&lt;h4 id=&quot;windowsdos&quot;&gt;Windows/DOS&lt;/h4&gt;

&lt;p&gt;Set your environment variables from your System Properties menu.&lt;/p&gt;

&lt;h3 id=&quot;command-line-options-method-3&quot;&gt;Command-line Options (method 3)&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ rudy-ec2 -A your_aws_key -S your_aws_secret COMMAND
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;NOTE: &lt;em&gt;If you use the command-line options, your credentials will appear in your shell history. You can run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;history -c&lt;/code&gt; to clear it.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;rudy-ec2--commands&quot;&gt;rudy-ec2  Commands&lt;/h2&gt;

&lt;p&gt;A &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rudy-ec2&lt;/code&gt; command follows the same convention as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rudy&lt;/code&gt; commands:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ rudy-ec2 -h
USAGE: rudy-ec2 [global options] COMMAND [command options]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The default command displays the current instances&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ rudy-ec2
i-8794fcee  ec2-11-22-33-44.compute-1.amazonaws.com  (group-awesome)
i-9e94fcf7  ec2-55-66-77-88.compute-1.amazonaws.com  (group-awesome)
i-9394fcfa  terminated  (group-awesome)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When no arguments are given, all commands display information about the object you specify:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ rudy-ec2 images
Images owned by amazon
aki-46e7002f i386   (aki-linux.2.6.21.7-2.fc8xen-xfs/vmlinuz.manifest.xml)
aki-9800e5f1 x86_64 (ec2-public-images/vmlinuz-2.6.18-xenU-ec2-v1.0.x86_64.aki.manifest.xml)
aki-9b00e5f2 i386   (ec2-public-images/vmlinuz-2.6.18-xenU-ec2-v1.0.i386.aki.manifest.xml)
...

$ rudy-ec2 groups
group-awesome (authorized accounts: 123456789012:default)
11.22.33.44/32 -&amp;gt; tcp(22), tcp(80), tcp(443)
55.66.77.88/32 -&amp;gt; tcp(22), tcp(80), tcp(443)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;With arguments, you can create, modify or destroy all EC2 objects:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ rudy-ec2 instances -C -m ami-235fba4a -s m1.small -k keypair-name
i-9394fcfa  pending  (default)

$ rudy-ec2 groups -A -p 8080,8081 group-awesome
Authorize access to group-awesome from 11.22.33.44/32
on tcp ports: 8080, 8081
default (authorized accounts: 123456789012:default)
   11.22.33.44/32 -&amp;gt; tcp(22), tcp(80), tcp(443), tcp(88), tcp(99)
   11.22.33.44/32 -&amp;gt; tcp(8080), tcp(8081)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;safety&quot;&gt;Safety&lt;/h2&gt;

&lt;p&gt;I’m always a little nervous using the Amazon AMI tools because I feel like I’m one command away from a nightmare. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rudy-ec2&lt;/code&gt; solves this by prompting for user input before executing any potentially destructive actions.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ rudy-ec2 groups -D group-awesome
Destroying group: group-awesome
Are you sure? To continue, resolve (7 * 5): 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And you can avoid the annoyance by providing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-Y&lt;/code&gt; global&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ rudy-ec2 -Y groups -D group-awesome    # Careful!
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;That’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rudy-ec2&lt;/code&gt; in a nutshell. For more information, check out the &lt;a href=&quot;http://opensource.solutious.com/rudy&quot;&gt;RDocs&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Rudy, not your grandparent's deployment tool</title>
   <link href="http://solutious.com/blog/2009/04/21/rudy-not-your-grandparents-deployment-tool/"/>
   <updated>2009-04-21T00:00:00+00:00</updated>
   <id>http://solutious.com/blog/2009/04/21/rudy-not-your-grandparents-deployment-tool</id>
   <content type="html">&lt;p&gt;&lt;em&gt;NOTE: This post is historically accurate but out of date. See: &lt;a href=&quot;/blog/2009/08/10/rudy-0.9-released/&quot;&gt;Rudy 0.9 Released&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://github.com/solutious/rudy&quot;&gt;Rudy&lt;/a&gt; is a command-line development and deployment tool. It’s been in private beta for about two months and today marks the day of the &lt;a href=&quot;http://github.com/solutious/rudy/tree/0.6&quot;&gt;first public release&lt;/a&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[1]&lt;/code&gt;. The project is still in alpha status and many features have yet to be developed but it’s already useful for exploring the features of Amazon EC2. In this post, I’ll introduce Rudy’s core features and demonstrate how these features can help build and manage environments in EC2.&lt;/p&gt;

&lt;h2 id=&quot;a-quick-look&quot;&gt;A quick look&lt;/h2&gt;

&lt;p&gt;It’s useful to know what working with Rudy looks like before getting into the details:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ rudy startup            # Launch the default machine group, stage-app
$ rudy -e dev startup     # Launch the dev-app machine group
$ rudy machines           # List all instances running in stage-app
$ rudy -u root ssh        # SSH to root@m-us-east-1b-stage-app-01
$ rudy ssh uptime         # Execute the uptime command on app stage-app machines
$ rudy shutdown           # Terminate stage-app instances
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;See also:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ rudy -h 
$ rudy show-commands
$ rudy COMMAND -h
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;machine-groups&quot;&gt;Machine Groups&lt;/h2&gt;

&lt;p&gt;Rudy helps you build and manage machines in EC2 by organizing them into groups of &lt;em&gt;environments&lt;/em&gt; and &lt;em&gt;roles&lt;/em&gt;. These are called &lt;em&gt;machine groups&lt;/em&gt;. You can run multiple machines with the same role. These are called &lt;em&gt;positions&lt;/em&gt;. Rudy also supports running machine groups across availability &lt;em&gt;zones&lt;/em&gt;. When you put all this together, you have a unique name for every machine. The default machine is:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;         zone     env  role
          v        v    v   
    m-us-east-1b-stage-app-01
    ^                       ^
 &quot;machine&quot;                position
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stage&lt;/code&gt; is the default environment and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;app&lt;/code&gt; is the default role, but these can be changed too (see Defaults below). These machine groups are configured using a Ruby DSL (domain-specific language) that looks like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;machines&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# Define two identical environments&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:dev&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:stage&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Default properties for all roles&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ami&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;ami-235fba4a&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;positions&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    
    &lt;span class=&quot;n&quot;&gt;role&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:app&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# Create two identical instances in the :app role. &lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;positions&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# Elastic IP addresses to be associated on startup&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;addresses&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;11.22.33.44&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;55.66.77.88&quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
    &lt;span class=&quot;n&quot;&gt;role&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:analyzer&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# The :analyzer machines can have their own AMI&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;ami&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;ami-********&quot;&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# Define EBS volumes for this machine&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;disks&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/data/disk1&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;device&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/dev/sdr&quot;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;    
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The configuration above describes the properties for 4 machine groups: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dev-app&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dev-analyzer&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stage-app&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stage-analyzer&lt;/code&gt;. Since we’ve defined two &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;app&lt;/code&gt; machines per environment, that makes 6 machines:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;m-us-east-1b-dev-app-01&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;m-us-east-1b-dev-app-02&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;m-us-east-1b-dev-analyzer-01&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;m-us-east-1b-stage-app-01&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;m-us-east-1b-stage-app-02&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;m-us-east-1b-stage-analyzer-01&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;routines&quot;&gt;Routines&lt;/h2&gt;

&lt;p&gt;The machines configuration describes the whats or the “physical” characteristics of the environments. The routines configuration describes the repeatable processes.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;routines&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# Define routines for the stage environment&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:stage&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;role&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:analyzer&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# Tell Rudy what to do when you run &quot;rudy startup&quot;&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;startup&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# Execute &quot;uname&quot; on the local machine&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;before_local&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Rudy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sysinfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:git&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:commit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'a'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'m'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Rudy Startup&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;before_local&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Rudy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sysinfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:git&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;disks&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
          &lt;span class=&quot;c1&quot;&gt;# Create an EBS volume, attach it, format it, and mount it&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;create&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/rudy/disk1&quot;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;after&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:username&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'/a/release/script'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;after&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:root&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'/etc/init.d/nginx'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'restart'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;shutdown&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;before&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:root&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/another/custom/script'&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;before&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:root&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:mysqladmin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:u&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'root'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'shutdown'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;disks&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
          &lt;span class=&quot;c1&quot;&gt;# Umount the volume, detach it, delete it&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;destroy&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/rudy/disk1&quot;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# Rudy.sysinfo.user returns the process' current user (ENV['user'])&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;after_local&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Rudy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sysinfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;date&quot;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;    
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This routines configuration describes the processes for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stage-analyzer&lt;/code&gt; group.&lt;/p&gt;

&lt;h2 id=&quot;running-a-routine&quot;&gt;Running a Routine&lt;/h2&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ rudy -r analyzer startup
Starting stage-app

---  BEFORE SCRIPTS (local)  ------------------------------
Connecting to localhost
...
Starting m-us-east-1b-stage-app-01
Associating 11.22.33.44 to i-11111111
Starting m-us-east-1b-stage-app-02
Associating 55.66.77.88 to i-22222222
....

---  DISK ROUTINES  ---------------------------------------
...

---  AFTER SCRIPTS  ---------------------------------------
...

The following machines are now available:
m-us-east-1b-stage-app-01  ec2-11-22-33-44.compute-1.amazonaws.com
m-us-east-1b-stage-app-02  ec2-55-66-77-88.compute-1.amazonaws.com
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;defaults&quot;&gt;Defaults&lt;/h2&gt;

&lt;p&gt;You may be wondering where the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;us-east-1b&lt;/code&gt; value comes from. This is an EC2 availability zone and it’s one of several default values that Rudy assumes in order to function straight “out of the box”. The default values can be changed too:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;defaults&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;region&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:&quot;us-east-1&quot;&lt;/span&gt; 
  &lt;span class=&quot;n&quot;&gt;zone&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:&quot;us-east-1b&quot;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:stage&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;role&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:app&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;position&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;01&quot;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ENV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'USER'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_sym&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;conclusion--more-to-come&quot;&gt;Conclusion / More to come&lt;/h2&gt;

&lt;p&gt;As I mentioned, the current release of Rudy (0.6) is in alpha status so it’s not ready for production. There’s a lot of work to do, including a lot of documentation to write, but hopefully you can already see the value of incorporating Rudy into your development process. For now, the &lt;a href=&quot;http://github.com/solutious/rudy&quot;&gt;README&lt;/a&gt; contains installation instructions and the &lt;a href=&quot;http://opensource.solutious.com/rudy&quot;&gt;RDocs&lt;/a&gt; are somewhat helpful too!&lt;/p&gt;

&lt;h2 id=&quot;notes&quot;&gt;Notes&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[1]&lt;/code&gt; Rudy has been available on GitHub since the project began, but this release is the first one with documentation.&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>From WordPress to Jekyll</title>
   <link href="http://solutious.com/blog/2009/04/10/wordpress-to-jekyll/"/>
   <updated>2009-04-10T00:00:00+00:00</updated>
   <id>http://solutious.com/blog/2009/04/10/wordpress-to-jekyll</id>
   <content type="html">&lt;p&gt;I started this blog in September 2008 with a post about &lt;a href=&quot;/2008/09/16/simple-ruby-encryption.html&quot;&gt;encryption in Ruby&lt;/a&gt;. I used &lt;a href=&quot;http://tumblr.com/&quot;&gt;Tumblr&lt;/a&gt; because I wanted something quick and simple. As it turned out, Tumblr is a great service for personal blogs but not for group and company blogs. Adding multiple users to a single blog with Tumblr is &lt;em&gt;strange&lt;/em&gt;. Every user must have their own personal blog before they can be added to the group blog. I also wanted more control over the layout and content.&lt;/p&gt;

&lt;p&gt;In December &lt;a href=&quot;/2008/12/12/tumblr-to-wordpress.html&quot;&gt;I switched to WordPress&lt;/a&gt;. It was a surprisingly pleasant experience. I could do almost everything I wanted to do with the layout and I brought the content home to our own servers. But something still did not feel right. I don’t particularly like databases at the best of times and using one for a blog is more than a bit excessive. There’s a lot of overhead involved in running a &lt;a href=&quot;http://wordpress.org/&quot;&gt;WordPress&lt;/a&gt; blog (the same thing can be said about any blog engine that combines an application with a database). There’s the system administration to keep it up to date, secure, and performing well. There are more steps than necessary to write new posts. It’s slow. That’s a lot of cake!&lt;/p&gt;

&lt;p&gt;So what’s the solution? &lt;a href=&quot;http://github.com/mojombo/jekyll&quot;&gt;Jekyll&lt;/a&gt;, a blog-aware, static site generator. What’s old is new again. I’ve been using Jekyll for &lt;a href=&quot;http://solutious.com&quot;&gt;solutious.com&lt;/a&gt; for about a month and I’m loving it. Unlike databases, I love files regardless of the times so using a static site is right up my alley. And now I’m using it for the blog too. There’s a lot &lt;a href=&quot;http://www.oiledmachine.com/posts/2008/12/27/overview-of-jekyll--a-static-site-generator-written-in-ruby.html&quot;&gt;of positive&lt;/a&gt; &lt;a href=&quot;http://blog.favrik.com/2009/03/02/installing-jekyll-on-ubuntu-8-10/&quot;&gt;and helpful&lt;/a&gt; &lt;a href=&quot;http://drnicwilliams.com/2008/12/21/migrating-project-websites-to-github-pages-with-sake-tasks-new-websites-with-jekyll_generator/&quot;&gt;stuff written&lt;/a&gt; &lt;a href=&quot;http://metajack.im/2009/01/23/blogging-with-git-emacs-and-jekyll/&quot;&gt;about it&lt;/a&gt; already so I won’t re-iterate that here. But I will mention that Jekyll also &lt;a href=&quot;http://github.com/blog/402-github-pages-upgraded-to-jekyll-0-5-0&quot;&gt;plays nice with GitHub&lt;/a&gt; (which is logical since it’s written by &lt;a href=&quot;http://tom.preston-werner.com/&quot;&gt;Tom Preston-Werner&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;I’ll also mention that I like the name. Thanks TPW!&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Installing sys-cpu 0.6.0 on OS X 10.5 Leopard</title>
   <link href="http://solutious.com/blog/2008/12/30/installing-sys-cpu-osx/"/>
   <updated>2008-12-30T00:00:00+00:00</updated>
   <id>http://solutious.com/blog/2008/12/30/installing-sys-cpu-osx</id>
   <content type="html">&lt;p&gt;I was trying to install the 
&lt;a href=&quot;http://rubyforge.org/projects/sysutils&quot; title=&quot;sysutils at Rubyforge&quot;&gt;sys-utils&lt;/a&gt; Ruby libraries today and got an error while building sys-cpu on OX 10.5 Leopard. sys-cpu is a multi-platform Ruby library for accessing information about the CPUs and it contains a native extension which needs to be compiled during them installation. This is the error:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo gem install sys-cpu
  Building native extensions.  This could take a while...
  ERROR:  Error installing sys-cpu:
  ERROR: Failed to build gem native extension.
  ...
  cpu.c:14:17: error: kvm.h: No such file or directory
  cpu.c:14:17: error: kvm.h: No such file or directory
  cpu.c: In function 'cpu_load_avg':
  ...
  make: *** [cpu.o] Error 1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;OS X 10.5 seems to be missing a C header file, kvm.h, that’s required by sys-cpu. Here’s how you can solve the problem:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Download a &lt;a href=&quot;http://rubyforge.org/frs/download.php/20065/sys-cpu-0.6.0.tar.gz&quot; title=&quot;sys-cpu tar.gz&quot;&gt;non-gem version&lt;/a&gt; and unpack it.&lt;/li&gt;
  &lt;li&gt;Get a copy of kvm.h. If you’re running OS X 10.5 that was upgraded from 10.4, you can find it in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/Developer/SDKs/MacOSX10.4.sdk/usr/include&lt;/code&gt;. If not, you can download it from here: &lt;a href=&quot;http://solutious.com/r/kvm.h&quot;&gt;http://solutious.com/r/kvm.h&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Copy kvm.h in to sys-cpu-0.6.0/ext&lt;/li&gt;
  &lt;li&gt;Inside of sys-cpu-0.6.0, run: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rake test&lt;/code&gt; then &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo rake install&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;The following command should now run without errors: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ruby -r'sys/cpu' -e 1&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s it!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>From Tumblr to WordPress</title>
   <link href="http://solutious.com/blog/2008/12/12/tumblr-to-wordpress/"/>
   <updated>2008-12-12T00:00:00+00:00</updated>
   <id>http://solutious.com/blog/2008/12/12/tumblr-to-wordpress</id>
   <content type="html">&lt;p&gt;We’re currently converting our blog from Tumblr to WordPress. We’re literally in the middle of it but I wanted to take a moment to explain why we’re moving and why we chose WordPress.&lt;/p&gt;

&lt;h2 id=&quot;why-were-moving-from-tumblr&quot;&gt;Why we’re moving from Tumblr&lt;/h2&gt;

&lt;p&gt;We accepted Tumblr’s strange management for group blogs and the broken archive page for FireFox. But there is one issue that is not excusable: &lt;strong&gt;extremely poor search engine performance&lt;/strong&gt;. This issue was brought up a few months ago by &lt;a href=&quot;http://www.16thletter.com/2008/05/08/why-im-kissing-tumblr-a-sad-sad-good-bye/&quot;&gt;Melissa Chang&lt;/a&gt;, a &lt;a href=&quot;http://friendfeed.com/e/bf7efe81-48eb-4bdc-629c-ee5c55a4a2f2/Why-I-m-kissing-Tumblr-a-sad-sad-good-bye-16th/&quot;&gt;flurry of discussion&lt;/a&gt; ensued, and Tumblr &lt;a href=&quot;http://staff.tumblr.com/post/35727451/weve-just-made-a-few-changes-to-make-your&quot;&gt;made some changes&lt;/a&gt; Erik Dafforn posted a &lt;a href=&quot;http://seoblog.intrapromote.com/2008/05/tumblr_and_seo.html&quot;&gt;more complete chronology&lt;/a&gt;). Seven months have passed and Tumblr search engine performance still sucks.&lt;/p&gt;

&lt;h2 id=&quot;why-wordpress&quot;&gt;Why WordPress&lt;/h2&gt;

&lt;p&gt;There’s surprisingly few choices. We looked at some Ruby options Mephisto, enki, Feather, all have strange quirks. We tried them all (and others) because we thought, “Hey it’s been a few years since we installed a blog there must be a new kid on the block”. The shocking answer is, &lt;em&gt;no, there’s not&lt;/em&gt; (if you’re looking for something with a reasonable installation process). Mephisto wants Rails 2.2.2. Feather has some issues with Merb and won’t install anyway because gems.datamapper.com seems to be down. Enki just wouldn’t run on Dreamhost (Passenger returned a vague error message but the logs contained nothing helpful). We thought we were on crazy pills but it appears to be reality!&lt;/p&gt;

&lt;p&gt;Why WordPress? &lt;em&gt;Because it works.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Update (2008-12-19): WordPress continues to treat us well. I can’t say the same for &lt;a href=&quot;http://disqus.com&quot;&gt;Disqus&lt;/a&gt; however. The wordpress plugin returns broken HTML for the comments_number function (which is why we don’t display the comment count on the left)&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Update (2009-04-12): We &lt;a href=&quot;/blog/2009/04/10/wordpress-to-jekyll/&quot;&gt;changed again&lt;/a&gt;. The blog is now powered by the static site generator &lt;a href=&quot;http://github.com/mojombo/jekyll&quot;&gt;Jekyll&lt;/a&gt;. Our comments are now powered by &lt;a href=&quot;http://intensedebate.com/&quot;&gt;Intense Debate&lt;/a&gt;. We finally made it home&lt;/em&gt;!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Using Amazon EC2 In Europe</title>
   <link href="http://solutious.com/blog/2008/12/10/using-amazon-ec2-in-europe/"/>
   <updated>2008-12-10T00:00:00+00:00</updated>
   <id>http://solutious.com/blog/2008/12/10/using-amazon-ec2-in-europe</id>
   <content type="html">&lt;p&gt;If you’re worked with EC2 before, there are a couple things you need to know to get started with launching machine instances in Europe. SSH Keys and AMIs are not shared between regions. We’re going to create both of these and then launch an instance in Europe. There’s also a new parameter &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--region&lt;/code&gt; which you need to use to interact with the new availability zones. Let’s giver’.&lt;/p&gt;

&lt;p&gt;##Create an S3 bucket in Europe##&lt;/p&gt;

&lt;p&gt;AMIs are stored in S3 so you need a bucket in Europe if you don’t have one already (you’ll probably want a new one for your machine images anyway). There’s a Firefox extension called &lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/3247&quot;&gt;S3Fox&lt;/a&gt; that can help you do this (check the box labeled, “Place this bucket in Europe”). Note that S3Fox is quirky and ugly almost to the point where it’s offensive. But it works and it’s easier than writing a script. The free version of &lt;a href=&quot;http://rightscale.com/&quot;&gt;RightScale&lt;/a&gt; can do this too. You can also use &lt;a href=&quot;http://s3tools.logix.cz/s3tools&quot;&gt;S3Tools&lt;/a&gt; to create buckets but I’ve never used them so I can’t recommend them.&lt;/p&gt;

&lt;p&gt;##Copy an AMI from the US to EU##&lt;/p&gt;

&lt;p&gt;You have two choices: re-bundle your running instance(s) or copy your existing images with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ec2-migrate-bundle&lt;/code&gt; tool. If you choose to re-bundle, follow the steps you normally would (described in the &lt;a href=&quot;http://docs.amazonwebservices.com/AWSEC2/2008-12-01/DeveloperGuide/index.html?bundling-an-ami-linux.html&quot;&gt;developer guide&lt;/a&gt;) and then upload the bundle to Europe (also in the &lt;a href=&quot;http://docs.amazonwebservices.com/AWSEC2/2008-12-01/DeveloperGuide/index.html?CLTRG-ami-upload-bundle.html&quot;&gt;developer guide&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;The easiest approach is to use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ec2-migrate-bundle&lt;/code&gt; tool. You’ll need to install the latest &lt;a href=&quot;http://developer.amazonwebservices.com/connect/entry.jspa?externalID=368&quot;&gt;AMI tools&lt;/a&gt; to a Linux or Windows machine near you (these &lt;em&gt;&lt;a href=&quot;http://developer.amazonwebservices.com/connect/message.jspa?messageID=92712&quot;&gt;will not work on OSX&lt;/a&gt;&lt;/em&gt;). As a side note, the AMI tools are written in Ruby which is interesting because the &lt;a href=&quot;http://developer.amazonwebservices.com/connect/entry.jspa?externalID=351&quot;&gt;API tools&lt;/a&gt; are written in Java.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ ec2-migrate-bundle --location EU --cert /mnt/cert-*.pem --privatekey /mnt/pk-*.pem \
--access-key ORANGEJUICE --secret-key SUp0rS3kRu7 \
--bucket BUCKET-IN-US --destination-bucket BUCKET-IN-EU \ 
--manifest IMAGE.manifest.xml 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note: If you’re running this command on an EC2 instance, you’ll need to upload your encryption keys first:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ scp -i PATH/2/private-key PATH/2/cert-*.pem PATH/2/pk-*.pem root@YOURMACHINE:/mnt/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;From your local machine, run the follow to tell EC2 that your new Europe image exists:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ ec2-register --region eu-west-1 BUCKET-IN-EU/IMAGE.manifest.xml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;##Update API Tools##&lt;/p&gt;

&lt;p&gt;You won’t be able to see your image yet b/c you need to update your &lt;a href=&quot;http://developer.amazonwebservices.com/connect/entry.jspa?externalID=351&quot;&gt;API tools&lt;/a&gt;. You should run these on a &lt;em&gt;real, physical machine&lt;/em&gt;. Why? Because it’s a good rule of thumb for keeping your keys secure. If you copy them to a machine instance, you could forget them and they could end up being available on every instance you startup.&lt;/p&gt;

&lt;p&gt;Now you’ll be able to see your machine images in Europe:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ ec2-describe-images --region eu-west-1 -o self
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You’ll be able to see the regions and availability zones:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ ec2-describe-regions
REGION	eu-west-1	eu-west-1.ec2.amazonaws.com
REGION	us-east-1	us-east-1.ec2.amazonaws.com

$ ec2-describe-availability-zones --region eu-west-1
AVAILABILITYZONE	eu-west-1a	 available	eu-west-1
AVAILABILITYZONE	eu-west-1b	 available	eu-west-1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can make Europe your default region by adding the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EC2_URL&lt;/code&gt; variable to your environment:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# Unix and Unix-like:
export EC2_URL=https://eu-west-1.ec2.amazonaws.com

# Windows:
set EC2_URL=https://eu-west-1.ec2.amazonaws.com
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;##Create an SSH key in Europe##&lt;/p&gt;

&lt;p&gt;Before you can launch an instance in Europe, you need to create a new SSH key:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ ec2-add-keypair eu-west-1-key --region eu-west-1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The output of this command is your private key. Save it in a secure location! You’ll need to make sure it’s only readable by you (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;chmod 600 eu-west-1-key&lt;/code&gt;). SSH won’t use it otherwise.&lt;/p&gt;

&lt;p&gt;##Create a security group in Europe##&lt;/p&gt;

&lt;p&gt;The default security group won’t allow you to SSH in to your new instance. You can create a new group with these commands:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ ec2-add-group --region eu-west-1 -d &quot;Potato Storage&quot; potato
GROUP	potato	Potato Storage

$ ec2-authorize --region eu-west-1 -p 22 potato
GROUP		potato	
PERMISSION		potato	ALLOWS	tcp	22	22	FROM	CIDR	0.0.0.0/0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If security groups are new to you, be sure to check out the &lt;a href=&quot;http://docs.amazonwebservices.com/AWSEC2/2008-12-01/DeveloperGuide/index.html?CLTRG-ami-migrate-bundle.html&quot;&gt;documentation&lt;/a&gt; and &lt;a href=&quot;http://docs.amazonwebservices.com/AmazonEC2/dg/2006-10-01/distributed-firewall-examples.html&quot;&gt;firewall examples&lt;/a&gt;. &lt;a href=&quot;http://broadcast.oreilly.com/2008/11/20-rules-for-amazon-cloud-security.html&quot;&gt;Twenty Rules for Amazon Cloud Security&lt;/a&gt; is a good read too.&lt;/p&gt;

&lt;p&gt;##Launch an instance in Europe (finally!)##&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ ec2-run-instances --region eu-west-1 --availability-zone eu-west-1b \
--key eu-west-1-key --group potato -t m1.small ami-XXXXXXXX
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Use the following command to see when it becomes available:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ ec2-describe-instances --region eu-west-1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Once it does, log in and have some fun!&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ ssh -i PATH/2/eu-west-1-key root@ec2-XX-XXX-XX-XXX.eu-west-1.compute.amazonaws.com
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;##Don’t forget to terminate the instance!##&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ ec2-terminate-instances --region eu-west-1 i-XXXXXXXX
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;##Extra Stuff##&lt;/p&gt;

&lt;p&gt;There’s more information about regions in the &lt;a href=&quot;http://developer.amazonwebservices.com/connect/entry.jspa?externalID=1927&amp;amp;categoryID=174&quot;&gt;Amazon EC2 Regions Guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Enjoy running your apps in style!&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>A Basic Voicemail System using Twilio</title>
   <link href="http://solutious.com/blog/2008/12/04/voicemail-with-twilio/"/>
   <updated>2008-12-04T00:00:00+00:00</updated>
   <id>http://solutious.com/blog/2008/12/04/voicemail-with-twilio</id>
   <content type="html">&lt;p&gt;We setup a voicemail system this week using &lt;a href=&quot;http://twilio.com/&quot;&gt;Twilio&lt;/a&gt;. There are &lt;a href=&quot;http://thethomashowecompany.com/449/twilio-comes-out&quot;&gt;other similar services&lt;/a&gt; but Twilio was the first one we’ve found that’s both available (&lt;a href=&quot;http://cloudvox.com/&quot;&gt;CloudVox&lt;/a&gt; is in private beta) and &lt;em&gt;really&lt;/em&gt; simple to get started.&lt;/p&gt;

&lt;p&gt;If you aren’t familiar with it, Twilio is a voice communication system with an &lt;a href=&quot;http://www.twilio.com/docs/api_reference/TwiML/&quot;&gt;HTTP/XML API&lt;/a&gt;. You create an account with them and they give you a phone number and an API key. Then you write some code that outputs XML (they have &lt;a href=&quot;http://www.twilio.com/docs/libraries/&quot;&gt;libraries for Ruby, Java, Python, and PHP&lt;/a&gt; and configure your account to point to an XML resource to handle the initial incoming call.  They charge $0.03 or $0.05 cents per minute depending on whether you’re using a local or toll free number.&lt;/p&gt;

&lt;p&gt;We’ve posted &lt;a href=&quot;http://gist.github.com/31922&quot;&gt;one of our test configurations&lt;/a&gt; to Gist (we blame the PHP on the intern :p sorry Dave). Here’s our initial feedback:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The XML is based on simple verbs (&lt;a href=&quot;http://www.twilio.com/docs/api_reference/TwiML/play&quot;&gt;Play&lt;/a&gt;, &lt;a href=&quot;http://www.twilio.com/docs/api_reference/TwiML/say&quot;&gt;Say&lt;/a&gt;, &lt;a href=&quot;http://www.twilio.com/docs/api_reference/TwiML/record&quot;&gt;Record&lt;/a&gt;…) so it’s easy to get started. I’ve read complaints about using XML in this way, usually on the basis that it’s over simplified and proprietary, but I disagree. If something can be simplified, simplify it. And if it’s easy to work with, the fact that it’s a proprietary language doesn’t matter. (On a side note, is there a standard, open language for controlling voice communication systems?)&lt;/li&gt;
  &lt;li&gt;The debugger is pretty cool. You can look at the recent requests and responses between their system and your web service. We solved two problems like this (XML encoding issues, &lt;em&gt;again&lt;/em&gt;).&lt;/li&gt;
  &lt;li&gt;The mp3s don’t play properly in Safari (we’re running 3.2.1). It displays a &lt;a href=&quot;http://farm4.static.flickr.com/3234/3081614839_acdda24cac.jpg?v=0&quot;&gt;black screen that says “No video”&lt;/a&gt;. Sometimes it will play after you hit the spacebar, sometimes not. Firefox is fine. &lt;em&gt;Update: this looks like it could be related to Flip4Mac, which I updated last week. The same thing is happening with other mp3s.&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;I somewhat concerned about jerks calling in many times or for long durations to charge up our bill. This is an issue with all similar services but I didn’t see anything in the docs or API that would prevent this in Twilio.&lt;/li&gt;
  &lt;li&gt;The prices are reasonable for moderate use but I expect they should decrease as their customer base increases (they should be able to negotiate lower rates from their suppliers).&lt;/li&gt;
  &lt;li&gt;Their customer service is excellent! We experienced it and so did our friends at &lt;a href=&quot;http://dealerdiagnostics.com/&quot;&gt;Dealer Diagnostics&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We’ll be looking at other options and we’ll post our findings here.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Sun's EC2 Support sucks</title>
   <link href="http://solutious.com/blog/2008/10/17/sun-ec2-support-sucks/"/>
   <updated>2008-10-17T00:00:00+00:00</updated>
   <id>http://solutious.com/blog/2008/10/17/sun-ec2-support-sucks</id>
   <content type="html">&lt;p&gt;So I’m pretty disappointed in Sun. I’ve made good things happen with OpenSolaris and EC2 separately and I was pretty excited about using them together. But we’ve been waiting for three weeks for a reply to my inquiry regarding &lt;a href=&quot;http://blog.solutious.com/post/51633311/ec2-disk-performance-linux-vs-opensolaris&quot;&gt;OpenSolaris I/O performance in Amazon EC2&lt;/a&gt;. I can only assume there’s an issue that they’re not ready to talk about because they were very responsive to other questions. This is an unwelcome contrast to the type of support we’re enjoying from Amazon.&lt;/p&gt;

&lt;p&gt;My advice: Stick with Linux on EC2.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>EC2 Disk Performance, Linux vs OpenSolaris -- Preliminary Results</title>
   <link href="http://solutious.com/blog/2008/09/23/ec2-disk-performance-linux-solaris/"/>
   <updated>2008-09-23T00:00:00+00:00</updated>
   <id>http://solutious.com/blog/2008/09/23/ec2-disk-performance-linux-solaris</id>
   <content type="html">&lt;p&gt;I started playing with the Solaris images on EC2 last week. I’m crazy for disk performance so I got straight to the benchmarking. These are only preliminary results because I’m only testing reading and writing medium to large files and I’m still getting a feel for the performance. In these tests I’m using the dd utility to read and write files to several mounts (local, local swap, and EBS). The test and results are below and I follow up with what will be improved on for the next test. NOTE: I’m currently waiting for a response from Sun’s EC2 support before continuing the tests.&lt;/p&gt;

&lt;p&gt;Summary: Reading and writing medium to large files in OpenSolaris in EC2 appears to be slower than Linux. More testing is required.&lt;/p&gt;

&lt;p&gt;##Tests##&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Read/write 10MB, 100MB, 1000MB to /, /mnt/, /data, /tmp&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;/ and /mnt are the default “local” disks&lt;/li&gt;
  &lt;li&gt;/tmp is the default “local” swap space&lt;/li&gt;
  &lt;li&gt;/data is an EBS volume (ext3 for linux, zfs for solaris)&lt;/li&gt;
  &lt;li&gt;See script &lt;a href=&quot;http://solutious.com/benchmarks/disktest1-sept.17.2008/disktest1.sh.txt&quot;&gt;disktest1.sh&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;##Machines##&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;m1.small, Fedora 8 Linux 32-bit (&lt;a href=&quot;http://solutious.com/benchmarks/disktest1-sept.17.2008/disktest1-linux-small.log&quot;&gt;test data&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;m1.small, OpenSolaris 2008.05 32-bit (no test data, killed after 20 minutes)&lt;/li&gt;
  &lt;li&gt;m1.large, Fedora 8 Linux 64-bit (&lt;a href=&quot;http://solutious.com/benchmarks/disktest1-sept.17.2008/disktest1-linux-large.log&quot;&gt;test data&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;m1.large, Solaris Express Community Edition build 79 64-bit (&lt;a href=&quot;http://solutious.com/benchmarks/disktest1-sept.17.2008/disktest1-solaris-large.log&quot;&gt;test data&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;##Conclusions##&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Local Disk performance: Linux is much faster.&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Linux vs OpenSolaris&lt;/li&gt;
  &lt;li&gt;OpenSolaris can be up to 30 times slower for 1GB+ files (2s vs 1m)&lt;/li&gt;
  &lt;li&gt;About the same for 10MB and 100MB files (~0.02s)&lt;/li&gt;
  &lt;li&gt;OpenSolaris swap (/tmp) performance is about 2x slower (2s vs 4s for 1GB)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Small Linux vs Large Linux&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Comparable for 10MB files&lt;/li&gt;
  &lt;li&gt;m1.small is amall is about 3x slower for 100MB files (0.6s vs 0.2s)&lt;/li&gt;
  &lt;li&gt;m1.small is amall is about 5-8x slower for 1000MB files (12s vs 2s)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Small OpenSolaris vs Large OpenSolaris&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The m1.small instance of OpenSolaris is really, really slow for all tests. I stopped the test after 20 minutes (note the m1.large OpenSolaris instance took 6.5 minutes)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;EBS Performance: Linux is faster.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Linux vs OpenSolaris&lt;/li&gt;
  &lt;li&gt;Solaris performance is about 2.5x slower (2s vs 5s for 1GB)&lt;/li&gt;
  &lt;li&gt;Small Linux vs Large Linux&lt;/li&gt;
  &lt;li&gt;m1.small is about 2x slower for 10MB (0.05s vs 0.025s)&lt;/li&gt;
  &lt;li&gt;m1.small is about 2-3x slower for 100MB (0.6s vs 0.2s)&lt;/li&gt;
  &lt;li&gt;m1.small is about 7x slower for 1GB (14s vs 2s)&lt;/li&gt;
  &lt;li&gt;Small Solaris vs Large Solaris&lt;/li&gt;
  &lt;li&gt;m1.small is REALLY slow.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;##Notes##&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The times grew longer for each of the 3 runs (the first run was always the fastest). Try again with a delay in between to account for some kind of background EC2/EBS process to finish.&lt;/li&gt;
  &lt;li&gt;There are occasional writes which are very slow for both platforms regardless of which test was being run.&lt;/li&gt;
  &lt;li&gt;The Solaris Express Community Edition is not supported.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;##What you can look forward to in the next test##&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Use standard public EC2 images. Include the ami ID and uname output for each test to be clear in the systems used.&lt;/li&gt;
  &lt;li&gt;Track the total run time for all tests (note: above I only have times for the two large instances).&lt;/li&gt;
  &lt;li&gt;Use bonnie-64 test to test caching / swapping performance.&lt;/li&gt;
  &lt;li&gt;Use bonnie++ for testing small file performance.&lt;/li&gt;
  &lt;li&gt;Restart instances between tests, define warm-up procedure.&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>Simple Encryption (in Ruby)</title>
   <link href="http://solutious.com/blog/2008/09/16/simple-ruby-encryption/"/>
   <updated>2008-09-16T00:00:00+00:00</updated>
   <id>http://solutious.com/blog/2008/09/16/simple-ruby-encryption</id>
   <content type="html">&lt;p&gt;I occasionally get questions on how we do authentication in Ruby so I thought I’d write this post so I could direct people here. A lot of the authentication stuff we do is based on this simple implementation of &lt;a href=&quot;http://blog.leetsoft.com/2006/03/14/simple-encryption&quot;&gt;RSA key support&lt;/a&gt;. There were a couple minor syntax errors in their &lt;a href=&quot;http://blog.leetsoft.com/files/crypto-key.rb.txt&quot;&gt;crypto-key.rb&lt;/a&gt; though so here’s a fixed version:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'openssl'&lt;/span&gt; 
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'base64'&lt;/span&gt;	&lt;span class=&quot;c1&quot;&gt;# Added &lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Crypto&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;create_keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;priv&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;rsa_key&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;priv&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.pub&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bits&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1024&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;private_key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;OpenSSL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;PKey&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;RSA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bits&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;priv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;w+&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;private_key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s2&quot;&gt;&quot;w+&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;private_key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;public_key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;    
    &lt;span class=&quot;n&quot;&gt;private_key&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Key&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;vi&quot;&gt;@public&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=~&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/^-----BEGIN (RSA|DSA) PRIVATE KEY-----$/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;nil?&lt;/span&gt;
      &lt;span class=&quot;vi&quot;&gt;@key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;OpenSSL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;PKey&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;RSA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;from_file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;    
      &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;encrypt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;no&quot;&gt;Base64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;encode64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key_type&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;_encrypt&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;decrypt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;vi&quot;&gt;@key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key_type&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;_decrypt&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Base64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;decode64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
 &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;private?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@public&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# Added () and ;&lt;/span&gt;

 &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;public?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;   &lt;span class=&quot;vi&quot;&gt;@public&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# Added () and ;&lt;/span&gt;
    
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;key_type&lt;/span&gt;
      &lt;span class=&quot;vi&quot;&gt;@public&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:public&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:private&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

</content>
 </entry>
 
 
</feed>