<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-8917931115554225973</id><updated>2012-02-10T07:13:27.418-08:00</updated><category term='ruby'/><category term='yui'/><category term='haml'/><category term='tcpdump'/><category term='tools'/><category term='javascript'/><category term='bugs'/><category term='DRY'/><category term='os x'/><category term='http'/><category term='curl'/><category term='sleep'/><category term='DOM'/><category term='css'/><category term='git'/><category term='shell'/><category term='nginx'/><category term='rails'/><category term='google sites'/><category term='carrierwave'/><category term='email'/><category term='database'/><category term='safari'/><category term='linux'/><category term='jQuery'/><category term='emacs'/><category term='rackspace'/><category term='mysql'/><category term='sass'/><category term='CI testing'/><category term='jammit'/><category term='hudson'/><category term='syntax highlighting'/><category term='compass'/><category term='cloud'/><category term='rubygems'/><category term='rhtml'/><category term='rspec'/><category term='timezone'/><category term='blogger'/><category term='geolocation'/><category term='hacks'/><category term='html'/><category term='ssl'/><category term='devise'/><category term='IE'/><category term='curb'/><category term='macports'/><category term='blogging'/><category term='prototype'/><title type='text'>Sleepless Coding</title><subtitle type='html'>A simple blog about the coding I do when I can't sleep.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://sleeplesscoding.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://sleeplesscoding.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>scottwb</name><uri>http://www.blogger.com/profile/07534230274246537772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dIGRXKsNGEw/SYiJAKXWsGI/AAAAAAAAABQ/27TDtjQwhfc/S220/mountain01.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>33</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8917931115554225973.post-6904596831673204096</id><published>2012-01-15T18:22:00.000-08:00</published><updated>2012-01-15T18:22:45.080-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='blogging'/><title type='text'>My Blog Has Moved</title><content type='html'>I will no longer be posting at this blog. The posts and comments will remain intact, but all new posts will happen at by new site: &lt;a href="http://scottwb.com/"&gt;http://scottwb.com&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8917931115554225973-6904596831673204096?l=sleeplesscoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sleeplesscoding.blogspot.com/feeds/6904596831673204096/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8917931115554225973&amp;postID=6904596831673204096&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/6904596831673204096'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/6904596831673204096'/><link rel='alternate' type='text/html' href='http://sleeplesscoding.blogspot.com/2012/01/my-blog-has-moved.html' title='My Blog Has Moved'/><author><name>scottwb</name><uri>http://www.blogger.com/profile/07534230274246537772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dIGRXKsNGEw/SYiJAKXWsGI/AAAAAAAAABQ/27TDtjQwhfc/S220/mountain01.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8917931115554225973.post-7166532694215769369</id><published>2011-09-04T11:33:00.000-07:00</published><updated>2011-09-04T11:33:28.017-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='carrierwave'/><title type='text'>Recreate a single version of a CarrierWave::Uploader file</title><content type='html'>CarrierWave supports a simple way to recreate all the versions of an uploaded file. This comes in handy when you add a new version to your uploader, or when you change the parameters of one of them. For example, assume you have a &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Post&lt;/span&gt; class, with a CarrierWave mounted uploader on the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;photo&lt;/span&gt; column, and you have version called &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;thumb&lt;/span&gt;. If you decide to change the resolution of the thumb version, and need to go back and regenerate all existing thumbs, you can do something like this:&lt;br /&gt;&lt;br /&gt;&lt;pre class="ruby" name="code"&gt;Post.all.each do |post|&lt;br /&gt;  post.photo.recreate_versions!&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;What if you have 5 different versions on this Uploader, and you only changed one of them? The above method will download all the versions of every &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Post#photo&lt;/span&gt; from storage (think S3 or Cloud Files), regenerate all of them - &lt;i&gt;even the ones that haven't changed&lt;/i&gt; - and re-upload all of them to storage.&lt;br /&gt;&lt;br /&gt;That's a lot of wasted time, CPU, and bandwidth.&lt;br /&gt;&lt;br /&gt;To address this, I've created a simple monkey patch for CarrierWave to provide a new method called &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;recreate_version!&lt;/span&gt;. This method works just like &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;recreate_versions!&lt;/span&gt;, except that it takes a parameter specifying a single version to recreate, rather than recreating all of them.&lt;br /&gt;&lt;br /&gt;To use this, first drop this monkey-patch in somewhere that it will get loaded. Above your Uploader class will suffice.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1193236.js?file=carrierwave_recreate_version.rb"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;Now your script to recompute all the thumbs can look like this:&lt;br /&gt;&lt;br /&gt;&lt;pre class="ruby" name="code"&gt;Post.all.each do |post|&lt;br /&gt;  post.photo.recreate_version!(:thumb)&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This will recreate and re-upload only the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;thumb&lt;/span&gt; versions of your &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Post#photo&lt;/span&gt; uploads.&lt;br /&gt;&lt;br /&gt;As an added side benefit, the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;recreate_version!&lt;/span&gt; method cleans up after itself. The &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;recreate_versions!&lt;/span&gt; method downloads into a temporary cache dir, but leaves it up to the caller to clean that up. This new method assumes that if it had to download and cache the uploaded file and its versions, then it should clean them up immediately.&lt;br /&gt;&lt;br /&gt;This method has turned out to save me a lot of time in regenerating large numbers of uploaded file versions. If there's any interest in this, I might work up a pull request with test cases and try to get it into the mainline CarrierWave gem release.&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8917931115554225973-7166532694215769369?l=sleeplesscoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sleeplesscoding.blogspot.com/feeds/7166532694215769369/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8917931115554225973&amp;postID=7166532694215769369&amp;isPopup=true' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/7166532694215769369'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/7166532694215769369'/><link rel='alternate' type='text/html' href='http://sleeplesscoding.blogspot.com/2011/09/recreate-single-version-of.html' title='Recreate a single version of a CarrierWave::Uploader file'/><author><name>scottwb</name><uri>http://www.blogger.com/profile/07534230274246537772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dIGRXKsNGEw/SYiJAKXWsGI/AAAAAAAAABQ/27TDtjQwhfc/S220/mountain01.jpg'/></author><thr:total>5</thr:total><georss:featurename>Kirkland, WA</georss:featurename><georss:point>47.6814875 -122.2087353</georss:point><georss:box>47.638726500000004 -122.2876993 47.7242485 -122.1297713</georss:box></entry><entry><id>tag:blogger.com,1999:blog-8917931115554225973.post-4510640679460318866</id><published>2011-08-23T22:04:00.000-07:00</published><updated>2011-08-23T23:24:04.555-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='devise'/><title type='text'>Adding filters to stock Devise controllers</title><content type='html'>Have some before_filters or after_filters you want to add to some or all of the Devise controller actions without having to subclass all the Devise controllers?&lt;br /&gt;&lt;br /&gt;Here's a little trick I use: directly call the &lt;span style="font-family:courier new;"&gt;before_filter&lt;/span&gt; or &lt;span style="font-family:courier new;"&gt;after_filter&lt;/span&gt; class methods in the &lt;span style="font-family:courier new;"&gt;devise.rb&lt;/span&gt; initializer. For example, I have a &lt;span style="font-family:courier new;"&gt;prepare_for_mobile&lt;/span&gt; method that I want to apply as a before_filter to all of the Devise controller actions. This is what I have at the bottom of &lt;span style="font-family:courier new;"&gt;config/initializers/devise.rb&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1167350.js?file=devise.rb"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;Note that this is exactly the same as if you had added the before_filter call directly inside these controllers. That means if you wanted to be more selective, you could just as easily do something like:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1167352.js?file=devise.rb"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;IMPORTANT NOTE:&lt;/span&gt; This tactic only works reliably in the production environment. That is because in development mode, the Devise controller classes get reloaded on each request, but this config file that we've edited does not.&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8917931115554225973-4510640679460318866?l=sleeplesscoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sleeplesscoding.blogspot.com/feeds/4510640679460318866/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8917931115554225973&amp;postID=4510640679460318866&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/4510640679460318866'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/4510640679460318866'/><link rel='alternate' type='text/html' href='http://sleeplesscoding.blogspot.com/2011/08/adding-filters-to-stock-device.html' title='Adding filters to stock Devise controllers'/><author><name>scottwb</name><uri>http://www.blogger.com/profile/07534230274246537772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dIGRXKsNGEw/SYiJAKXWsGI/AAAAAAAAABQ/27TDtjQwhfc/S220/mountain01.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8917931115554225973.post-701533055177578341</id><published>2011-08-21T14:21:00.000-07:00</published><updated>2011-08-21T14:44:59.226-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='bugs'/><category scheme='http://www.blogger.com/atom/ns#' term='cloud'/><category scheme='http://www.blogger.com/atom/ns#' term='carrierwave'/><category scheme='http://www.blogger.com/atom/ns#' term='hacks'/><category scheme='http://www.blogger.com/atom/ns#' term='ssl'/><category scheme='http://www.blogger.com/atom/ns#' term='rackspace'/><title type='text'>Rackspace Cloud Files SSL Failures Over ServiceNet</title><content type='html'>I recently switched from using the public interface on my Rackspace Cloud Server to using the private interface (a.k.a. ServiceNet) for uploading files from my instance to Cloud Files. When I made this switch, I started noticing a number of intermittent "Connection reset by peer" errors.&lt;br /&gt;&lt;br /&gt;I have reproduced this problem with both the `Fog` and `ruby-cloudfiles` gems.&lt;br /&gt;&lt;br /&gt;To upload to Cloud Files, I'm using CarrierWave, which uses Fog, which uses Excon. With those, the error looks something like this:&lt;br /&gt;&lt;pre name="code" class="ruby"&gt;Excon::Errors::SocketError: Connection reset by peer - SSL_connect&lt;br /&gt;&lt;br /&gt;[GEM_ROOT]/gems/excon-0.6.4/lib/excon/connection.rb:264:in `connect'&lt;br /&gt;[GEM_ROOT]/gems/excon-0.6.4/lib/excon/connection.rb:264:in `open_ssl_socket'&lt;br /&gt;[GEM_ROOT]/gems/excon-0.6.4/lib/excon/connection.rb:243:in `connect'&lt;br /&gt;[GEM_ROOT]/gems/excon-0.6.4/lib/excon/connection.rb:282:in `socket'&lt;br /&gt;[GEM_ROOT]/gems/excon-0.6.4/lib/excon/connection.rb:156:in `request'&lt;br /&gt;[GEM_ROOT]/gems/fog-0.9.0/lib/fog/core/connection.rb:20:in `request'&lt;br /&gt;[GEM_ROOT]/gems/fog-0.9.0/lib/fog/storage/rackspace.rb:102:in `request'&lt;br /&gt;[GEM_ROOT]/gems/fog-0.9.0/lib/fog/storage/requests/rackspace/put_object.rb:19:in `put_object'&lt;br /&gt;[GEM_ROOT]/gems/fog-0.9.0/lib/fog/storage/models/rackspace/file.rb:59:in `save'&lt;br /&gt;[GEM_ROOT]/gems/fog-0.9.0/lib/fog/core/collection.rb:50:in `create'&lt;br /&gt;[GEM_ROOT]/gems/carrierwave-0.5.6/lib/carrierwave/storage/fog.rb:229:in `store'&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I never really narrowed down why this is happening, but it seems to happen only after a period of inactivity. I.e.: it fails once, then works fine as long as I keep making requests, but after 10+ minutes, the next request fails again.&lt;br /&gt;&lt;br /&gt;Since I am only storing files to Rackspace Cloud Files via CarrierWave, the most expedient thing for me to do was to wrap the storage call in CarrierWave with some exception handling to retry these failures. It's a hack, but it works like a charm and saved me at crunch time:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1161210.js?file=carrierwave_fog_hack.rb"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;Even if you're not using CarrierWave or Fog, this concept could work for you. Of course, you may use more operations that just storing files, and you'll probably have to wrap those too.&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8917931115554225973-701533055177578341?l=sleeplesscoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sleeplesscoding.blogspot.com/feeds/701533055177578341/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8917931115554225973&amp;postID=701533055177578341&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/701533055177578341'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/701533055177578341'/><link rel='alternate' type='text/html' href='http://sleeplesscoding.blogspot.com/2011/08/rackspace-cloud-files-ssl-failures-over.html' title='Rackspace Cloud Files SSL Failures Over ServiceNet'/><author><name>scottwb</name><uri>http://www.blogger.com/profile/07534230274246537772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dIGRXKsNGEw/SYiJAKXWsGI/AAAAAAAAABQ/27TDtjQwhfc/S220/mountain01.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8917931115554225973.post-4797190405354576163</id><published>2011-08-18T14:33:00.000-07:00</published><updated>2011-08-18T15:06:57.623-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cloud'/><category scheme='http://www.blogger.com/atom/ns#' term='rackspace'/><title type='text'>Performance of Rackspace Cloud Files Upload Over Private Network</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-fw1ZZ0Qt-BE/Tk2Ml3tefSI/AAAAAAAAAK0/gWZOuR1-xgA/s1600/rackspace.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 199px; height: 200px;" src="http://1.bp.blogspot.com/-fw1ZZ0Qt-BE/Tk2Ml3tefSI/AAAAAAAAAK0/gWZOuR1-xgA/s200/rackspace.png" alt="" id="BLOGGER_PHOTO_ID_5642320490402839842" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Does using the private network interface on a Rackspace Cloud Server instance to transfer data into Rackspace Cloud files save you anything?&lt;br /&gt;&lt;br /&gt;I am certain it saves you money. You pay for outgoing bandwidth on your Cloud Server instance's public IP address, but not on the private one. But, I've also read that it is much faster to use the private IP, or "ServiceNet" as they call it. "Lightning fast" even. So, I tried make a quick-and-dirty benchmark to see for myself.&lt;br /&gt;&lt;br /&gt;In short, I don't think it makes much difference, considering the margin of error. Here are the results of a typical test run that shows the timings of uploads of a 1MB file alternating over the public and private interfaces, with a cumulative time printed out at the bottom:&lt;br /&gt;&lt;br /&gt;&lt;a href="https://gist.github.com/1155335"&gt;https://gist.github.com/1155335&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;That example is the most sane run of many test runs I did with this script. What is more disconcerting is that both public and private have wild outliers. Sometimes a transfer that normally takes a tenth of a second can take 30 seconds or even two minutes!&lt;br /&gt;&lt;br /&gt;Check out this test run: &lt;a href="https://gist.github.com/1155349"&gt;https://gist.github.com/1155349&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Whoa! The 31st upload took 132 seconds! In my experience over multiple runs, the private snet almost always comes out way ahead. It seems like it is just as likely to have 10-second outliers, but less likely to have 30+ second outliers.&lt;br /&gt;&lt;br /&gt;If you are interested in reproducing my tests, you can get the code at: &lt;a href="https://github.com/scottwb/cloudfiles-snet-bench"&gt;https://github.com/scottwb/cloudfiles-snet-bench&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;On caveat to this test, other than generally not being very scientific, is that I am not using large files (which is the use case I am actually interested in). It is possible that large transfers may get big speed gains over the private servicenet.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8917931115554225973-4797190405354576163?l=sleeplesscoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sleeplesscoding.blogspot.com/feeds/4797190405354576163/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8917931115554225973&amp;postID=4797190405354576163&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/4797190405354576163'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/4797190405354576163'/><link rel='alternate' type='text/html' href='http://sleeplesscoding.blogspot.com/2011/08/performance-of-rackspace-cloud-files.html' title='Performance of Rackspace Cloud Files Upload Over Private Network'/><author><name>scottwb</name><uri>http://www.blogger.com/profile/07534230274246537772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dIGRXKsNGEw/SYiJAKXWsGI/AAAAAAAAABQ/27TDtjQwhfc/S220/mountain01.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-fw1ZZ0Qt-BE/Tk2Ml3tefSI/AAAAAAAAAK0/gWZOuR1-xgA/s72-c/rackspace.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8917931115554225973.post-8797560660281531251</id><published>2011-08-16T23:35:00.000-07:00</published><updated>2011-08-16T23:48:24.411-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='http'/><category scheme='http://www.blogger.com/atom/ns#' term='bugs'/><category scheme='http://www.blogger.com/atom/ns#' term='hacks'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><title type='text'>Rails incorrectly parses HTTP Accept header for single media with range</title><content type='html'>Try hitting your Rails app with an HTTP header like this:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="ruby"&gt;Accept: text/html;q=0.7&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;You will most likely get an exception that looks something like this:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="ruby"&gt;Missing template home/index with {:locale=&amp;gt;[:en, :en],  :formats=&amp;gt;["text/html;q=0.7"], :handlers=&amp;gt;[:rhtml, :erb, :haml,  :rxml, :builder, :rjs]} in view paths  "/path/to/my_app/app/views"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This is because the ActionPack &lt;span style="font-family:courier new;"&gt;Mime::Type&lt;/span&gt; class is buggy in the way it parses this header when there is only one media type specified, and that media type has a range specified (the ";q=0.7"). This is perfectly valid HTML, and ActionPack actually handles the ranges correctly when there are more than one type specified.&lt;br /&gt;&lt;br /&gt;An issue has been open for a while on this: &lt;a href="https://github.com/rails/rails/issues/736"&gt;https://github.com/rails/rails/issues/736&lt;/a&gt; -- working patches have been proposed but not applied, yet the issue got closed for some reason.&lt;br /&gt;&lt;br /&gt;I prefer not to patch my own version of Rails, so instead I am using a small monkey patch that works around this problem. I've created a file named &lt;span style="font-family:courier new;"&gt;config/initializers/rails_issue_736.rb&lt;/span&gt; that fixes the &lt;span style="font-family:courier new;"&gt;Mime::Type.lookup&lt;/span&gt; method to only use the part that comes before the semi-colon:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1150932.js?file=rails_issue_736.rb"&gt;&lt;/script&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8917931115554225973-8797560660281531251?l=sleeplesscoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sleeplesscoding.blogspot.com/feeds/8797560660281531251/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8917931115554225973&amp;postID=8797560660281531251&amp;isPopup=true' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/8797560660281531251'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/8797560660281531251'/><link rel='alternate' type='text/html' href='http://sleeplesscoding.blogspot.com/2011/08/rails-incorrectly-parses-http-accept.html' title='Rails incorrectly parses HTTP Accept header for single media with range'/><author><name>scottwb</name><uri>http://www.blogger.com/profile/07534230274246537772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dIGRXKsNGEw/SYiJAKXWsGI/AAAAAAAAABQ/27TDtjQwhfc/S220/mountain01.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8917931115554225973.post-9170015550607132918</id><published>2011-08-15T14:42:00.001-07:00</published><updated>2011-08-15T15:03:43.905-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rubygems'/><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='email'/><category scheme='http://www.blogger.com/atom/ns#' term='haml'/><category scheme='http://www.blogger.com/atom/ns#' term='sass'/><category scheme='http://www.blogger.com/atom/ns#' term='html'/><category scheme='http://www.blogger.com/atom/ns#' term='compass'/><category scheme='http://www.blogger.com/atom/ns#' term='css'/><title type='text'>MailMatic: HTML emails using Haml and Sass</title><content type='html'>Developing static HTML emails is a pain in the butt. For best results, you need to inline all of your styles at HTML attributes instead of using real CSS (externally or inline). You also typically find yourself being very repetitive with your markup if you have a bunch of static emails that share common elements.&lt;br /&gt;&lt;br /&gt;&lt;a href="https://github.com/scottwb/mailmatic"&gt;MailMatic&lt;/a&gt; to the rescue.&lt;br /&gt;&lt;br /&gt;MailMatic is a Ruby gem, that is really just a mashup of tools, that aims to ease the burden of creating and maintaining static HTML emails. It uses &lt;a href="https://github.com/staticmatic/staticmatic"&gt;StaticMatic&lt;/a&gt;, &lt;a href="http://haml-lang.com/"&gt;Haml&lt;/a&gt;, &lt;a href="http://sass-lang.com/"&gt;Sass&lt;/a&gt;, and &lt;a href="http://compass-style.org/"&gt;Compass&lt;/a&gt; to let you author your HTML emails with all of the facilities you enjoy while creating your dynamic site: templates, partials, helper functions, inline Ruby code, reuse of markup and styles, etc. It uses &lt;a href="https://github.com/alexdunae/premailer"&gt;Premailer&lt;/a&gt; to convert the HTML/CSS generated from Haml/Sass into self-contained HTML files that inline all of their styles. Premailer even gives you warnings about styles that may not work nicely in certain email readers.&lt;br /&gt;&lt;br /&gt;Armed with this, you can accelerate your ability to crank out static HTML emails, and lessen the burden of maintaining them.&lt;br /&gt;&lt;br /&gt;To get started with MailMatic, check out its installation and usage instructions on github at: &lt;a href="https://github.com/scottwb/mailmatic"&gt;https://github.com/scottwb/mailmatic&lt;/a&gt;.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8917931115554225973-9170015550607132918?l=sleeplesscoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sleeplesscoding.blogspot.com/feeds/9170015550607132918/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8917931115554225973&amp;postID=9170015550607132918&amp;isPopup=true' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/9170015550607132918'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/9170015550607132918'/><link rel='alternate' type='text/html' href='http://sleeplesscoding.blogspot.com/2011/08/mailmatic-html-emails-using-haml-and.html' title='MailMatic: HTML emails using Haml and Sass'/><author><name>scottwb</name><uri>http://www.blogger.com/profile/07534230274246537772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dIGRXKsNGEw/SYiJAKXWsGI/AAAAAAAAABQ/27TDtjQwhfc/S220/mountain01.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8917931115554225973.post-1081364061012383104</id><published>2011-07-19T21:18:00.000-07:00</published><updated>2011-07-20T09:15:32.111-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rubygems'/><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='timezone'/><category scheme='http://www.blogger.com/atom/ns#' term='geolocation'/><title type='text'>The ask_geo gem: find the time zone for a given latitude and longitude</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://upload.wikimedia.org/wikipedia/commons/thumb/9/9f/Tz_map_world2009r_efeledotnet.png/800px-Tz_map_world2009r_efeledotnet.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 800px; height: 408px;" src="http://upload.wikimedia.org/wikipedia/commons/thumb/9/9f/Tz_map_world2009r_efeledotnet.png/800px-Tz_map_world2009r_efeledotnet.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://code.google.com/apis/maps/index.html"&gt;Google Maps API&lt;/a&gt; has all kinds of great services like geocoding and reverse geocoding, but it lacks an API to determine a timezone from a latitude and longitude. This kind of service would come in handy, for example, when you are picking a point on Earth and scheduling an event there in the point's local time. It could also be useful for automatically determining a website visitor's current local time based on the geolocation obtained from their browser or IP address.&lt;br /&gt;&lt;br /&gt;There is a service called &lt;a href="http://www.geonames.org/export/web-services.html"&gt;GeoNames&lt;/a&gt;, which comes close to serving this need. However, its look-ups are based on "closest point of interest", which means that you can get errors when you are near borders, and some locations may not return any results at all.&lt;br /&gt;&lt;br /&gt;There is another service called &lt;a href="http://www.earthtools.org/webservices.htm"&gt;EarthTools&lt;/a&gt; which doesn't have this problem, but it only returns the current offset from UTC at that point. That is great if you only care about the current local time, but leaves you stranded if you need to account for Daylight Savings Time on some future or past date.&lt;br /&gt;&lt;br /&gt;After a bit of searching, I came across a great free service called &lt;a href="http://www.askgeo.com/"&gt;AskGeo&lt;/a&gt;. AskGeo provides a very simple JSON-over-HTTP API (or XML if you prefer to party like it's 1999). AskGeo uses a real time zone map, so every point on earth returns a result, and returns real &lt;a href="http://en.wikipedia.org/wiki/Tz_database"&gt;Olson IDs&lt;/a&gt; for time zones, so you can look up DST transitions, leap seconds, etc.&lt;br /&gt;&lt;br /&gt;I gave AskGeo a try and it works great...and it's fast! Since there was no ready-made Ruby gem that provided a client API, I decided to create one.&lt;br /&gt;&lt;br /&gt;Introducing the ask_geo gem: &lt;a href="https://github.com/scottwb/ask_geo"&gt;https://github.com/scottwb/ask_geo&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;It can be installed as a &lt;a href="https://rubygems.org/gems/ask_geo"&gt;ruby gem&lt;/a&gt;. See &lt;a href="https://github.com/scottwb/ask_geo"&gt;the github page&lt;/a&gt; for installation and usage instructions.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8917931115554225973-1081364061012383104?l=sleeplesscoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sleeplesscoding.blogspot.com/feeds/1081364061012383104/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8917931115554225973&amp;postID=1081364061012383104&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/1081364061012383104'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/1081364061012383104'/><link rel='alternate' type='text/html' href='http://sleeplesscoding.blogspot.com/2011/07/askgeo-gem-find-time-zone-for-given.html' title='The ask_geo gem: find the time zone for a given latitude and longitude'/><author><name>scottwb</name><uri>http://www.blogger.com/profile/07534230274246537772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dIGRXKsNGEw/SYiJAKXWsGI/AAAAAAAAABQ/27TDtjQwhfc/S220/mountain01.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8917931115554225973.post-8554100286004189146</id><published>2011-07-10T18:10:00.000-07:00</published><updated>2011-07-10T18:26:58.534-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='rspec'/><category scheme='http://www.blogger.com/atom/ns#' term='carrierwave'/><category scheme='http://www.blogger.com/atom/ns#' term='CI testing'/><title type='text'>Custom RSpec be_square matcher for CarrierWave</title><content type='html'>It seems to me that when using CarrierWave for image uploads, particularly user avatars, it would be a pretty common thing to generate at least one square-cropped version of the image. CarrierWave ships with some nice custom matchers to test exact dimensions and such, but I found I wanted a way to just test that an image was square.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I did this using by building a custom matcher on top of the ones CarrierWave provides. If you have the conventional &lt;span class="Apple-style-span" &gt;spec_helper.rb&lt;/span&gt; that requires &lt;span class="Apple-style-span" &gt;support/**/*.rb&lt;/span&gt;, then you can just drop this somewhere like &lt;span class="Apple-style-span" &gt;support/matchers/carrierwave_matchers.rb&lt;/span&gt;:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1075177.js?file=carrierwave_matchers.rb"&gt;&lt;/script&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Then, you can use this like:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1075180.js?file=avatar_uploader_spec.rb"&gt;&lt;/script&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8917931115554225973-8554100286004189146?l=sleeplesscoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sleeplesscoding.blogspot.com/feeds/8554100286004189146/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8917931115554225973&amp;postID=8554100286004189146&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/8554100286004189146'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/8554100286004189146'/><link rel='alternate' type='text/html' href='http://sleeplesscoding.blogspot.com/2011/07/custom-rspec-besquare-matcher-for.html' title='Custom RSpec be_square matcher for CarrierWave'/><author><name>scottwb</name><uri>http://www.blogger.com/profile/07534230274246537772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dIGRXKsNGEw/SYiJAKXWsGI/AAAAAAAAABQ/27TDtjQwhfc/S220/mountain01.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8917931115554225973.post-5292050906310086697</id><published>2011-05-31T11:48:00.000-07:00</published><updated>2011-05-31T12:16:23.841-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rubygems'/><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='http'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><title type='text'>Encrypted Cookie Store that works with Rails 3.0</title><content type='html'>If you like the benefits using Rails's CookieStore, but want to store possibly sensitive data in the cookie, then encrypted_cookie_store is for you. It works like CookieStore, but encrypts the cookie payload so that it cannot be read by the client.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you are using Ruby on Rails 3.0.0 or higher (but not yet Rails 3.1), then you'll need my fork of encrypted_cookie_store that fixes it for Rails 3.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;To install it:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;pre class="ruby" name="code"&gt;gem install scottwb-encrypted_cookie_store&lt;/pre&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Then add to your bundler Gemfile:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;pre class="ruby" name="code"&gt;gem 'scottwb-encrypted_cookie_store', :require =&amp;gt; 'encrypted_cookie_store'&lt;/pre&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Then read the rest of the &lt;a href="https://github.com/scottwb/encrypted_cookie_store/blob/master/README.md"&gt;installation/configuration instructions&lt;/a&gt;.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size:large;"&gt;Background&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;For Rails 2.3, the folks at Phusion created &lt;a href="https://github.com/FooBarWidget/encrypted_cookie_store"&gt;encrypted_cookie_store&lt;/a&gt;, which you'd install as a plugin, and it worked great. I used it for a long time.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;However, they never updated it for Rails 3. That's where &lt;a href="https://github.com/twoism-dev"&gt;Ben Sales&lt;/a&gt; came in. He &lt;a href="https://github.com/twoism-dev/encrypted_cookie_store"&gt;forked this project&lt;/a&gt; and made it work for Rails 3...in the pre-release days, that is. Ben did all the work to get it packaged up as a gem and updated it to work with Rails 3 railties and initializers.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Unfortunately, &lt;a href="https://github.com/rails/rails/commit/25f7c030e4ea440ea6c2a84c92118299753392d9#actionpack/lib/action_dispatch/middleware/session/cookie_store.rb"&gt;sometime between Rails 3.0.0.beta3 and 3.0.0.beta4&lt;/a&gt;, the layout of AbstractStore and CookieStore changed quite a bit, pushing a lot of the functionality out to Rack, and breaking the encrypted_cookie_store gem.&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;That's where I come in. I basically did the minimal amount of work required to get it to work with Rails 3.0 (tested on 3.0.0, 3.0.7, and 3.0.8.rc4), got all the specs working again, and created a new gem called 'scottwb-encrypted_session_cookie'.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It doesn't work in Rails 3.1, but I'll probably remedy that once Rails 3.1 officially releases. I'm also happy to accept patches if anyone else onces to tackle that.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This is a nice gem. Maybe some day I'll make a push to clean it up and lobby to have it as one of the packaged options that ships with Rails...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8917931115554225973-5292050906310086697?l=sleeplesscoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sleeplesscoding.blogspot.com/feeds/5292050906310086697/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8917931115554225973&amp;postID=5292050906310086697&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/5292050906310086697'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/5292050906310086697'/><link rel='alternate' type='text/html' href='http://sleeplesscoding.blogspot.com/2011/05/encrypted-cookie-store-that-works-with.html' title='Encrypted Cookie Store that works with Rails 3.0'/><author><name>scottwb</name><uri>http://www.blogger.com/profile/07534230274246537772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dIGRXKsNGEw/SYiJAKXWsGI/AAAAAAAAABQ/27TDtjQwhfc/S220/mountain01.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8917931115554225973.post-614363854093581435</id><published>2011-03-30T07:57:00.000-07:00</published><updated>2011-03-30T08:03:42.536-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='git'/><title type='text'>How to delete a remote git tag</title><content type='html'>I suppose this is probably taboo. You're not supposed to mess with tags once you've pushed them upstream. Still, there are times when it is necessary, and unfortunately `git push --tags` does not push the local removal of tags upstream. It always takes me forever to figure this out, so I figured I'd write it down. Maybe someone else will find it useful.&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="ruby"&gt;&lt;br /&gt;  git tag -d tag-to-delete&lt;br /&gt;  git push origin :refs/tags/tag-to-delete&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This will remove that tag from the remote repository. You can verify this by pulling from the remote again and seeing that it does not get pulled back down.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8917931115554225973-614363854093581435?l=sleeplesscoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sleeplesscoding.blogspot.com/feeds/614363854093581435/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8917931115554225973&amp;postID=614363854093581435&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/614363854093581435'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/614363854093581435'/><link rel='alternate' type='text/html' href='http://sleeplesscoding.blogspot.com/2011/03/how-to-delete-remote-git-tag.html' title='How to delete a remote git tag'/><author><name>scottwb</name><uri>http://www.blogger.com/profile/07534230274246537772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dIGRXKsNGEw/SYiJAKXWsGI/AAAAAAAAABQ/27TDtjQwhfc/S220/mountain01.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8917931115554225973.post-167640614334016406</id><published>2011-02-10T20:09:00.000-08:00</published><updated>2011-02-10T20:19:25.455-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><title type='text'>Rails-like number_with_delimiter in javascript</title><content type='html'>The number_with_delimiter view helper is Rails is nice. I wanted to do the same thing in Javascript. I went to just grab it from Rails and port it to js. But first I googled and found someone had already done exactly that. I took his code and made it extend Number.protoype so you can do something like:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="javascript"&gt;&lt;br /&gt;var num = 12345678;&lt;br /&gt;var str = num.number_with_delimiter();&lt;br /&gt;alert(str);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This will show that str is "12,345,678".&lt;br /&gt;&lt;br /&gt;Her's my version of the code:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/821904.js?file=number_with_delimiter.js"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;Based on code from: &lt;a href="http://kevinvaldek.com/number-with-delimiter-in-javascript"&gt;http://kevinvaldek.com/number-with-delimiter-in-javascript&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8917931115554225973-167640614334016406?l=sleeplesscoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sleeplesscoding.blogspot.com/feeds/167640614334016406/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8917931115554225973&amp;postID=167640614334016406&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/167640614334016406'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/167640614334016406'/><link rel='alternate' type='text/html' href='http://sleeplesscoding.blogspot.com/2011/02/rails-like-numberwithdelimiter-in.html' title='Rails-like number_with_delimiter in javascript'/><author><name>scottwb</name><uri>http://www.blogger.com/profile/07534230274246537772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dIGRXKsNGEw/SYiJAKXWsGI/AAAAAAAAABQ/27TDtjQwhfc/S220/mountain01.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8917931115554225973.post-3129592149671884204</id><published>2011-01-27T21:48:00.000-08:00</published><updated>2011-01-27T22:18:07.106-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='bugs'/><category scheme='http://www.blogger.com/atom/ns#' term='yui'/><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='hacks'/><category scheme='http://www.blogger.com/atom/ns#' term='jammit'/><category scheme='http://www.blogger.com/atom/ns#' term='css'/><title type='text'>YUI Compressor breaks CSS3 Media Query Syntax</title><content type='html'>If you use the CSS3 Media Query Syntax for something like this:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="css"&gt;&lt;br /&gt;@media screen and (max-device-width: 480px) {&lt;br /&gt;  body {font-size: 18px;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;You will find that when you compress this with &lt;a href="http://developer.yahoo.com/yui/compressor/"&gt;YUI Compressor&lt;/a&gt; (as is done when packaging your assets with &lt;a href="http://documentcloud.github.com/jammit/"&gt;Jammit&lt;/a&gt;), that the output breaks this syntax. YUI Compressor removes the whitespace between the "and" and the opening parenthesis, which does not conform to &lt;a href="http://www.w3.org/TR/css3-mediaqueries/"&gt;the CSS3 standard&lt;/a&gt;, and renders those styles unusable in most browsers (tested in Chrome and Safari, read about others hitting this in Firefox).&lt;br /&gt;&lt;br /&gt;There's a YUI Compressor bug filed here that covers this: &lt;a href="http://yuilibrary.com/projects/yuicompressor/ticket/2528053"&gt;http://yuilibrary.com/projects/yuicompressor/ticket/2528053&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;My Workaround&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;I am invoking YUI Compressor via an asset-packager called Jammit. In a &lt;a href="http://sleeplesscoding.blogspot.com/2011/01/jammit-compass-and-safari-cant-we-all.html"&gt;blog post yesterday&lt;/a&gt;, I noted some problems I encountered with Jammit not handling duplicate @charset directives generated by Sass/Compass, and outlined a quick hack workaround I used to deal with it.&lt;br /&gt;&lt;br /&gt;Today, encountering this @media-related bug leads to an additional workaround I had to add to that. So, I figured I'd share a bit of my resulting rake task that combines all of these.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;  &lt;li&gt;Use compass to compile my Sass to CSS &lt;span style="font-style:italic;"&gt;without compressing it (this is important)&lt;/span&gt;&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Use sed to remove all @charset directives (dangerous, but I know I don't need them in this case). Take care to make sure the differences in how the -i parameter to sed works between OS X and Linux.&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Use jammit to package up everything.&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;For each permutation (e.g.: normal, datauri) CSS package jammit generated, use sed to add the missing space back in to offending @media directives.&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;For each of those CSS files we sed-edited, re-gzip them. (Jammit made gzipped versions originally, but we have to regenerate them since we changed the contents.)&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Here's the final rake task:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/799901.js?file=assets.rake"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8917931115554225973-3129592149671884204?l=sleeplesscoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sleeplesscoding.blogspot.com/feeds/3129592149671884204/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8917931115554225973&amp;postID=3129592149671884204&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/3129592149671884204'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/3129592149671884204'/><link rel='alternate' type='text/html' href='http://sleeplesscoding.blogspot.com/2011/01/yui-compressor-breaks-css3-media-query.html' title='YUI Compressor breaks CSS3 Media Query Syntax'/><author><name>scottwb</name><uri>http://www.blogger.com/profile/07534230274246537772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dIGRXKsNGEw/SYiJAKXWsGI/AAAAAAAAABQ/27TDtjQwhfc/S220/mountain01.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8917931115554225973.post-2179581664790143372</id><published>2011-01-26T15:17:00.000-08:00</published><updated>2011-01-26T15:52:28.246-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bugs'/><category scheme='http://www.blogger.com/atom/ns#' term='hacks'/><category scheme='http://www.blogger.com/atom/ns#' term='safari'/><category scheme='http://www.blogger.com/atom/ns#' term='sass'/><category scheme='http://www.blogger.com/atom/ns#' term='jammit'/><category scheme='http://www.blogger.com/atom/ns#' term='compass'/><category scheme='http://www.blogger.com/atom/ns#' term='css'/><title type='text'>Jammit, Compass, and Safari: Can't we all just get along?</title><content type='html'>When &lt;a href="http://documentcloud.github.com/jammit/"&gt;Jammit&lt;/a&gt; is used with CSS files generated by &lt;a href="http://compass-style.org/"&gt;Compass&lt;/a&gt;, the resulting CSS file may not work with Safari. This is because every &lt;a href="http://sass-lang.com/"&gt;Sass&lt;/a&gt; file that includes Compass will add the following line to the top of the generated CSS file:&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;    &lt;pre class="code"&gt;    @charset "UTF-8";&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;That happens because something in Compass requires UTF-8, and Sass will generate that line if anything it is processing requires UTF-8. This is all fine...until you try to combine more than one of these standalone-css files with an asset packager such as Jammit.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Once Jammit combines all these CSS files, you end up with one CSS file that has multiple @charset directives in it, which according to the &lt;a href="http://www.w3.org/International/questions/qa-css-charset"&gt;W3&lt;/a&gt;, is a no-no. Generating a CSS file with more than one @charset directive (and anywhere other than the very first line) is clearly against the W3's spec...but the only browser it seems to break is Safari.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;But here's the thing: why do my CSS files need to have the @charset added by Sass when they don't actually get output with any non-ASCII characters?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In the end, my quick stop-gap solution was to remove them myself. I used to let Jammit do all the driving. During deployment it would force the regeneration of the CSS files and package them. Now I have to break out the Compass step and add my own sed command in order to remove all the @charset directives:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/797776.js?file=jammit.sh"&gt;&lt;/script&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I think each one of these components has something to improve:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Safari:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;If you don't support multiple @charset directives, I support you on that front. The spec says you're right. However...can't you just raise an error that says "ERROR: multiple @charset directives" or something? That would be much better than just randomly disabling half the CSS styles.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Sass:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;Sass shouldn't add a @charset line if the generated CSS does not need it. If a mixin that uses UTF-8 is included but not used, and is not represented in the generated CSS, there is no need to add a @charset directive on its behalf.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Compass:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;Compass is probably doing nothing wrong here. Though I do question why it needs to use UTF-8 characters. Maybe that's for a feature I haven't used yet.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Jammit:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;In the end, I think Jammit is the real culprit here. It takes in N perfectly-valid CSS files and outputs one invalid CSS file. Jammit should remove duplicate @charset directives, and if they are conflicting, it should convert the charset of the conflicting stylesheet and into the charset being used by the output file.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8917931115554225973-2179581664790143372?l=sleeplesscoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sleeplesscoding.blogspot.com/feeds/2179581664790143372/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8917931115554225973&amp;postID=2179581664790143372&amp;isPopup=true' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/2179581664790143372'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/2179581664790143372'/><link rel='alternate' type='text/html' href='http://sleeplesscoding.blogspot.com/2011/01/jammit-compass-and-safari-cant-we-all.html' title='Jammit, Compass, and Safari: Can&apos;t we all just get along?'/><author><name>scottwb</name><uri>http://www.blogger.com/profile/07534230274246537772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dIGRXKsNGEw/SYiJAKXWsGI/AAAAAAAAABQ/27TDtjQwhfc/S220/mountain01.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8917931115554225973.post-2787072050403644879</id><published>2011-01-25T08:38:00.000-08:00</published><updated>2011-01-25T09:25:41.374-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='http'/><category scheme='http://www.blogger.com/atom/ns#' term='bugs'/><category scheme='http://www.blogger.com/atom/ns#' term='IE'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='nginx'/><title type='text'>Workaround an IE bug: Redirecting subdomains to www while preserving virtual hosts (Nginx, Rails)</title><content type='html'>I ran into an interesting redirect configuration problem that was exacerbated by Internet Explorer's handing of cookies, which led me to move all subdomain redirection logic out of my Rails app and into Nginx. In the end, this feels like a good thing anyway. If you just want the conclusion, skip to the solution section.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Background&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;My original setup was to have nginx have virtual hosts for www.example.com, test.example.com, and staging.example.com, where the www.example.com was the default one that would catch anything else such as foo.example.com, or just example.com. Then the Rails app at www.example.com would check the URI in a before_filter and redirect to www.example.com, using a solution similar to the one described here: &lt;a href="http://stackoverflow.com/questions/327122/redirect-myapp-com-to-www-myapp-com-in-rails-without-using-htaccess"&gt;http://stackoverflow.com/questions/327122/redirect-myapp-com-to-www-myapp-com-in-rails-without-using-htaccess&lt;/a&gt;.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;h3&gt;Problem&lt;/h3&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The problem arose when an Internet Explorer user hit the site via http://example.com (i.e.: without the "www." prefix). Here is what happens when someone hits example.com in this setup:&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;The default virtual host for www.example.com picks up the request and hands it to the Rails app.&lt;/li&gt;&lt;li&gt;The Rails app's before_filter sees that the request.host does not start with 'www', and does a redirect.&lt;/li&gt;&lt;li&gt;Somewhere the ActionController internals set a session cookie on the domain "example.com" -- even though this before_filter redirects BEFORE any code tries to touch the session. (Perhaps this is an artifact of using CookieStore.)&lt;/li&gt;&lt;li&gt;The browser stores the session cookie for example.com, the follows the redirect to www.example.com, sending that cookie (which is basically an empty session at this point).&lt;/li&gt;&lt;li&gt;The user logs in. The Rails app sets stuff in the session and returns a response that sets the new session cookie with the new session, for www.example.com.&lt;/li&gt;&lt;li&gt;The browser now has two session cookies: One not-logged-in one for example.com, and one logged-in one for www.example.com.&lt;/li&gt;&lt;li&gt;The next page load is where the problems start...&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;div&gt;On Safari, Chrome, and Firefox, the next page load, on www.example.com, only sends the session cookie that is for www.example.com...and all is well. However, on Internet Explorer (tested on IE8 and IE9 beta), the browser sends BOTH session cookies, which both have the same name. In my observation, Rails always choose the first one, which is always the LEAST specific one - the one for example.com. Now, even though the user just logged in, he is not logged in.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I don't know what the HTTP RFC for user agents says about this, but I am just gonna go ahead and call this in IE bug. According to an &lt;a href="http://blogs.msdn.com/b/ieinternals/archive/2009/08/20/wininet-ie-cookie-internals-faq.aspx"&gt;MSDN FAQ about IE's cookie-handling&lt;/a&gt;, IE is different than other browsers, and they're just fine with that (see Q3 on that page). Also see Q1 where they say they don't even try to support the RFC for cookies.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Similar problems have been documented on the web. I read &lt;a href="http://arstechnica.com/civis/viewtopic.php?f=20&amp;amp;t=1126381"&gt;somewhere&lt;/a&gt; that if your Rails app redirects before touching the session, that you won't have this problem. That's not the case for me, but I suspect that may have to do with using CookieStore. I can imagine that CookieStore touches the session by reading it when it comes time to generate the cookie, and that this gets triggered even after a redirect.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;h3&gt;Redirect with Nginx&lt;/h3&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Since I could not get Rails to NOT set a cookie for example.com, I decided I would do this redirect in nginx. There are plenty of &lt;a href="http://www.debrice.com/tip/view/13/"&gt;examples&lt;/a&gt; on the web about redirecting example.com to www.example.com, or vice-versa. However, most of them don't work for my needs for one particular reason: virtual hosts.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In my scenario, I can't redirect ALL requests to non-www subdomains to the www-subdomain, because I have other virtual hosts on specific sub-domains that should not be re-routed. However, I can't simply enumerate the ones that I want redirected, since that is meant to be a catch-all. Rather than try to maintain a regular expression that matches all subdomains except the ones I setup virtual hosts on, I decided to just test the hostname inside the default virtual host, as shown in the conclusion section below. This way, specific subdomains get routed to the right virtual host, anything else gets routed to the www.example.com virtual host, and within that one, anything that isn't www.example.com gets redirected to www.example.com.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;h3&gt;Solution&lt;/h3&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The final solution: this nginx config mockup shows how I can have specific subdomains handled by their virtual hosts, and everything else redirected to the www subdomain.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/795176.js?file=nginx_subdomain.conf"&gt;&lt;/script&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8917931115554225973-2787072050403644879?l=sleeplesscoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sleeplesscoding.blogspot.com/feeds/2787072050403644879/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8917931115554225973&amp;postID=2787072050403644879&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/2787072050403644879'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/2787072050403644879'/><link rel='alternate' type='text/html' href='http://sleeplesscoding.blogspot.com/2011/01/workaround-ie-bug-redirecting.html' title='Workaround an IE bug: Redirecting subdomains to www while preserving virtual hosts (Nginx, Rails)'/><author><name>scottwb</name><uri>http://www.blogger.com/profile/07534230274246537772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dIGRXKsNGEw/SYiJAKXWsGI/AAAAAAAAABQ/27TDtjQwhfc/S220/mountain01.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8917931115554225973.post-9170656487672134011</id><published>2011-01-25T08:10:00.000-08:00</published><updated>2011-01-25T08:23:08.336-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='http'/><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='tcpdump'/><title type='text'>Using tcpdump to sniff HTTP traffic from a specific host</title><content type='html'>This is mostly just a reminder to myself about my preferred parameters to &lt;span class="Apple-style-span"&gt;tcpdump&lt;/span&gt; on linux, so that I don't have to keep reading the man page.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;pre name="code"&gt;tcpdump -c 20 -s 0 -i eth1 -A host 192.168.1.1 and tcp port http&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The parameter breakdown:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span"&gt;-c 20&lt;/span&gt;: Exit after capturing 20 packets.&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"&gt;-s 0&lt;/span&gt;: Don't limit the amount of payload data that is printed out. Print it all.&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"&gt;-i eth1&lt;/span&gt;: Capture packets on interface eth1&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"&gt;-A&lt;/span&gt;: Print packets in ASCII.&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"&gt;host 192.168.1.1&lt;/span&gt;: Only capture packets coming to or from 192.168.1.1.&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"&gt;and tcp port http&lt;/span&gt;: Only capture HTTP packets.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8917931115554225973-9170656487672134011?l=sleeplesscoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sleeplesscoding.blogspot.com/feeds/9170656487672134011/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8917931115554225973&amp;postID=9170656487672134011&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/9170656487672134011'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/9170656487672134011'/><link rel='alternate' type='text/html' href='http://sleeplesscoding.blogspot.com/2011/01/using-tcpdump-to-sniff-http-traffic.html' title='Using tcpdump to sniff HTTP traffic from a specific host'/><author><name>scottwb</name><uri>http://www.blogger.com/profile/07534230274246537772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dIGRXKsNGEw/SYiJAKXWsGI/AAAAAAAAABQ/27TDtjQwhfc/S220/mountain01.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8917931115554225973.post-6852732123380061170</id><published>2010-12-10T23:10:00.001-08:00</published><updated>2010-12-10T23:19:43.376-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='emacs'/><title type='text'>Hate the emacs tilde backup files?</title><content type='html'>I do...but for decades I have been afraid to turn them off in case I ever needed the backup file, even though I have never used them once. Finally I snapped and tried to figure out how to turn them off. While looking this up, I came across a better option: store them all in a single hidden directory, instead of littering the whole filesystem with them. There is a nice package called "backup-dir" that even provides the ability to keep multiple versions of your backup files, while keeping them all out of sight and out of mind, and automatically cleaning up old versions. Learn more at:&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.emacswiki.org/emacs/BackupDirectory"&gt;http://www.emacswiki.org/emacs/BackupDirectory&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;To see how I pulled in the &lt;span class="Apple-style-span" &gt;backup-dir&lt;/span&gt; package and set it up in my init.el file, see &lt;a href="https://github.com/scottwb/dotfiles/commit/54e6a05d061e05aae3b4a320fb23290857656f49"&gt;the change to my dotfiles project&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8917931115554225973-6852732123380061170?l=sleeplesscoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sleeplesscoding.blogspot.com/feeds/6852732123380061170/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8917931115554225973&amp;postID=6852732123380061170&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/6852732123380061170'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/6852732123380061170'/><link rel='alternate' type='text/html' href='http://sleeplesscoding.blogspot.com/2010/12/hate-emacs-tilde-backup-files.html' title='Hate the emacs tilde backup files?'/><author><name>scottwb</name><uri>http://www.blogger.com/profile/07534230274246537772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dIGRXKsNGEw/SYiJAKXWsGI/AAAAAAAAABQ/27TDtjQwhfc/S220/mountain01.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8917931115554225973.post-4018748615796590336</id><published>2010-12-08T18:21:00.000-08:00</published><updated>2010-12-08T18:34:06.565-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='git'/><title type='text'>Creating/Deleting local and remote branches with git</title><content type='html'>In the course of my git-based workflow, more often than not, I use branches like this:&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Create a new local branch starting from the HEAD of my current working branch.&lt;/li&gt;&lt;li&gt;Immediately push it upstream to the remote origin so that it exists in both places.&lt;/li&gt;&lt;li&gt;Set the local branch to track the remote branch.&lt;/li&gt;&lt;li&gt;Commit/push/repeat&lt;/li&gt;&lt;li&gt;Merge the branch back into master (or wherever it started from)&lt;/li&gt;&lt;li&gt;Delete the local branch.&lt;/li&gt;&lt;li&gt;Push to delete the remote branch.&lt;/li&gt;&lt;/ul&gt;Since this seems pretty common, and some of the commands to do this are a bit difficult to remember sometimes, I created two simple scripts called &lt;a href="https://github.com/scottwb/dotfiles/blob/master/bin/git-branch-create"&gt;git-branch-create&lt;/a&gt; and &lt;a href="https://github.com/scottwb/dotfiles/blob/master/bin/git-branch-delete"&gt;git-branch-delete&lt;/a&gt; to help with this. Now my workflow looks like:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;i&gt;git branch-create feature_branch&lt;/i&gt;&lt;/li&gt;&lt;li&gt;Commit/push/repeat.&lt;/li&gt;&lt;li&gt;Merge branch back into parent branch.&lt;/li&gt;&lt;li&gt;&lt;i&gt;git branch-delete feature_branch&lt;/i&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;To use these scripts via the above commands, download the scripts above and place them somewhere in your path. I even created short aliases for them like so:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;script src="https://gist.github.com/734254.js?file=gistfile1.sh"&gt;&lt;/script&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8917931115554225973-4018748615796590336?l=sleeplesscoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sleeplesscoding.blogspot.com/feeds/4018748615796590336/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8917931115554225973&amp;postID=4018748615796590336&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/4018748615796590336'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/4018748615796590336'/><link rel='alternate' type='text/html' href='http://sleeplesscoding.blogspot.com/2010/12/creatingdeleting-local-and-remote.html' title='Creating/Deleting local and remote branches with git'/><author><name>scottwb</name><uri>http://www.blogger.com/profile/07534230274246537772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dIGRXKsNGEw/SYiJAKXWsGI/AAAAAAAAABQ/27TDtjQwhfc/S220/mountain01.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8917931115554225973.post-5368037398483277191</id><published>2010-12-04T11:35:00.000-08:00</published><updated>2010-12-04T12:06:24.380-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rubygems'/><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='macports'/><category scheme='http://www.blogger.com/atom/ns#' term='curl'/><category scheme='http://www.blogger.com/atom/ns#' term='os x'/><category scheme='http://www.blogger.com/atom/ns#' term='curb'/><title type='text'>Installing curb gem on Mac OS X 10.6 (Snow Leopard)</title><content type='html'>If you have previously installed curl with something like:&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;pre name="code"&gt;    sudo port install curl +ssl&lt;/pre&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;and then try to install the curb gem like:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;pre name="code"&gt;    sudo gem install curb&lt;/pre&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;and you find yourself getting an error that looks something like this:&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;pre name="code"&gt;&lt;br /&gt;    In file included from /opt/local/include/curl/curl.h:44,&lt;br /&gt;                     from curb.h:12,&lt;br /&gt;                     from curb.c:8:&lt;br /&gt;    /opt/local/include/curl/curlrules.h:144: error: size of array ‘__curl_rule_01__’ is negative&lt;br /&gt;    /opt/local/include/curl/curlrules.h:154: error: size of array ‘__curl_rule_02__’ is negative&lt;br /&gt;    lipo: can't open input file: /var/folders/wX/wX64Cb+PGjG-EXuklO+I+k+++TI/-Tmp-//ccKIrqTY.out (No such file or directory)&lt;br /&gt;    make: *** [curb.o] Error 1&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Then, I think I have a solution for you. &lt;span style="font-weight:bold;"&gt;&lt;span style="font-style:italic;"&gt;Change your curb install command to this instead:&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;pre name="code"&gt;    sudo env ARCHFLAGS="-Os -arch x86_64 -fno-common" gem install curb&lt;/pre&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It seems a number of people on the web suggest re-installing curl as a universal binary using something like:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;pre name="code"&gt;    sudo port install zlib +universal&lt;br /&gt;    sudo port upgrade --enforce-variants openssl +universal&lt;br /&gt;    sudo port install curl +universal&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;b&gt;I do not like this approach.&lt;/b&gt;&lt;/i&gt; The original problem is that you installed an x86_64 version of curl (which is the default, &lt;i&gt;as it should be&lt;/i&gt;) but you are trying to install a universal version of curb (which is &lt;i&gt;unfortunately&lt;/i&gt; the default). Instead of re-installing curl to be universal, which is wasteful and takes forever, install curb using the x86_64 flags to build it. This is what you want, it works, and it only takes a few seconds.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8917931115554225973-5368037398483277191?l=sleeplesscoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sleeplesscoding.blogspot.com/feeds/5368037398483277191/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8917931115554225973&amp;postID=5368037398483277191&amp;isPopup=true' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/5368037398483277191'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/5368037398483277191'/><link rel='alternate' type='text/html' href='http://sleeplesscoding.blogspot.com/2010/12/installing-curb-gem-on-mac-os-x-106.html' title='Installing curb gem on Mac OS X 10.6 (Snow Leopard)'/><author><name>scottwb</name><uri>http://www.blogger.com/profile/07534230274246537772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dIGRXKsNGEw/SYiJAKXWsGI/AAAAAAAAABQ/27TDtjQwhfc/S220/mountain01.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8917931115554225973.post-3916591569327181748</id><published>2010-09-21T12:08:00.000-07:00</published><updated>2010-09-21T12:29:58.975-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mysql'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='database'/><title type='text'>Huge speed gain migrating large tables in Rails</title><content type='html'>Have you ever needed to make multiple column adds/removes/changes to a large table in Rails in a single migration? If so, you've probably noticed that each of these individual changes issues a single ALTER TABLE command to the database, which can take a long time on a large table. At least with MySQL, combining these all into a single ALTER TABLE dramatically reduces the amount of time it takes for your migration to run.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Rather than write custom SQL for this, the folks at &lt;a href="http://devblog.xing.com/"&gt;XING&lt;/a&gt; have created a very cool Rails plugin called &lt;a href="http://github.com/xing/alter_table"&gt;alter_table&lt;/a&gt;. Their blog post, &lt;a href="http://devblog.xing.com/ruby/alter-table-rails-plugin/"&gt;Alter Table Rails Plugin&lt;/a&gt;, gives more background on this. Check it out, it's a good, quick read.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;One thing they didn't mention in their post was what kind of performance gains they observed. I was curious, so I did a quick-and-dirty experiment.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Consider an existing table named "songs" that has 330K records in it. First, I tried just adding a column named "foo" using the normal migration style we're all accustomed to:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;script src="http://gist.github.com/590351.js?file=gistfile1.rb"&gt;&lt;/script&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;On my MacBook Pro, this is what the timings for this looked like:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;script src="http://gist.github.com/590352.js?file=gistfile1.txt"&gt;&lt;/script&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now, after rolling that back, installing the alter_table plugin (as per their instructions), I rewrote this migration to use the new alter_table method:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;script src="http://gist.github.com/590353.js?file=gistfile1.rb"&gt;&lt;/script&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now, on the same machine, this migration takes roughly half the time because it does all the alterations in a single pass. Here are the new timings:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;script src="http://gist.github.com/590354.js?file=gistfile1.txt"&gt;&lt;/script&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In real life, I had a table with almost 10 million rows that I needed to do 10 alterations to. Using this plugin, I cut my migration time down by almost 10x! If you find yourself doing more than one alteration on the same table in a single migration, I highly recommend checking out alter_table. You can find their source code at:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;blockquote&gt;&lt;a href="http://github.com/xing/alter_table"&gt;http://github.com/xing/alter_table&lt;/a&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8917931115554225973-3916591569327181748?l=sleeplesscoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sleeplesscoding.blogspot.com/feeds/3916591569327181748/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8917931115554225973&amp;postID=3916591569327181748&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/3916591569327181748'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/3916591569327181748'/><link rel='alternate' type='text/html' href='http://sleeplesscoding.blogspot.com/2010/09/huge-speed-gain-migrating-large-tables.html' title='Huge speed gain migrating large tables in Rails'/><author><name>scottwb</name><uri>http://www.blogger.com/profile/07534230274246537772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dIGRXKsNGEw/SYiJAKXWsGI/AAAAAAAAABQ/27TDtjQwhfc/S220/mountain01.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8917931115554225973.post-7739353535139143867</id><published>2010-08-23T13:39:00.001-07:00</published><updated>2010-08-23T13:48:32.974-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='hacks'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><title type='text'>Enumerate all Rails ActiveRecord::Base model classes</title><content type='html'>I couldn't quickly find an easy way to enumerate all ActiveRecord::Base-derived model classes in my Rails project (for some simple analysis scripts), so I whipped up this quick and dirty solution.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/546281.js?file=enum_models.rb"&gt;&lt;/script&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I extended ActiveRecord::Base just out of convenience, so I can call &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ActiveRecord::Base.each_model_class{|klass| ...}&lt;/span&gt; easily. You could apply the same technique in another class if you don't like extending Rails core classes.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The "rescue nil" is just a quick hack to catch the cases where you have tables that don't map to classes directly.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;NOTE: This does NOT enumerate STI-based model classes that don't have their own tables.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8917931115554225973-7739353535139143867?l=sleeplesscoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sleeplesscoding.blogspot.com/feeds/7739353535139143867/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8917931115554225973&amp;postID=7739353535139143867&amp;isPopup=true' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/7739353535139143867'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/7739353535139143867'/><link rel='alternate' type='text/html' href='http://sleeplesscoding.blogspot.com/2010/08/enumerate-all-rails-activerecordbase.html' title='Enumerate all Rails ActiveRecord::Base model classes'/><author><name>scottwb</name><uri>http://www.blogger.com/profile/07534230274246537772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dIGRXKsNGEw/SYiJAKXWsGI/AAAAAAAAABQ/27TDtjQwhfc/S220/mountain01.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8917931115554225973.post-6529204314009074424</id><published>2010-08-07T11:44:00.000-07:00</published><updated>2010-08-07T14:04:23.858-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='bugs'/><category scheme='http://www.blogger.com/atom/ns#' term='hacks'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><title type='text'>Rails 2.3 ActiveSupport::Cache::MemoryStore Freezes Objects</title><content type='html'>&lt;div style="text-align: left;"&gt;Using &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;MemoryStore&lt;/span&gt; for caching in Rails 2.3.X has what I would consider a show-stopper bug. When you write an object to the cache using &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Rails.cache.write&lt;/span&gt;, the original object gets frozen. When you read that object from the cache, it is also frozen. So, if you do something like read/write-through a cache for all your ActiveRecord models, you'll never be able to modify any instances of your models in your code.&lt;/div&gt;&lt;br /&gt;This same behavior is not present in other cache storage classes such as &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ActiveSupport::Cache::MemCacheStore&lt;/span&gt;. I don't think I'd ever use &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;MemoryStore&lt;/span&gt; in production...but it is great for testing. When running all of my rspecs and cucumber features, I have those environments set to use &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;MemoryStore&lt;/span&gt;. The problem is, many of my tests break when they try to modify objects that were frozen by the cache.&lt;br /&gt;&lt;br /&gt;Here's a simple example demonstrating this. Look at the WTFs on lines 10 and 14 of the output below:&lt;br /&gt;&lt;script src="http://gist.github.com/513051.js?file=gistfile1.txt"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;The Attempted Fix&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;It turns out this bug was filed (and partially fixed) a long time ago. Rails &lt;a href="https://rails.lighthouseapp.com/projects/8994/tickets/2655-railscache-freezes-all-objects-passed-to-it"&gt;ticket #2655&lt;/a&gt; was filed back in May 2009 about this exact issue. Yehuda Katz and Carl Lerche from EngineYard &lt;a href="http://github.com/rails/rails/commit/1026d7706ffb467eac3cee8142d964bc2d30baa8"&gt;committed a fix&lt;/a&gt; for this (to duplicate the object into the cache instead of freezing it) on July 1, 2009.&lt;br /&gt;&lt;br /&gt;This is great. It fixes line 10 in the example output above. However, it is not quite enough if you are putting &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ActiveRecord::Base&lt;/span&gt; objects into the cache because the object's &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;@attributes&lt;/span&gt; hash needs to be dup'd too. It turns out, the "carlhuda" pair was well aware of this and &lt;a href="http://github.com/rails/rails/commit/16dc139caa9286638785469304a69ab77e4fe9b5"&gt;committed a fix&lt;/a&gt; for that too, just moments before the other one.&lt;br /&gt;&lt;br /&gt;Another problem still remains though. Their fix still involves freezing the duplicate object in the cache and directly returning that frozen object. We need one more change to the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;read&lt;/span&gt; method to duplicate the object on the way out too. I made &lt;a href="http://github.com/scottwb/rails/commit/46f73da7815b9ee9c84d871ef50a356d849161a3"&gt;such a fix&lt;/a&gt; and updated the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;test_store_objects_should_be_immutable&lt;/span&gt; test for &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;MemoryStore&lt;/span&gt; to be consistent with that of &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;MemCacheStore&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The final problem is that carlhuda's commits never got merged into the Rails 2.3 branch. A quick look at the &lt;a href="http://github.com/rails/rails/network"&gt;github network graph for the rails project&lt;/a&gt; on July 1, 2009 tells the story.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238); -webkit-text-decorations-in-effect: underline; "&gt;&lt;a href="http://img.skitch.com/20100807-c5m47abjaffmbe32u6up74dt3s.png"&gt;&lt;img src="http://3.bp.blogspot.com/_dIGRXKsNGEw/TF3CeBA7_ZI/AAAAAAAAAIg/fOnJGsQODBc/s400/The+rails+Network+-+GitHub.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5502768140640845202" style="display: block; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; text-align: center; cursor: pointer; width: 400px; height: 102px; " /&gt;&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;div style="text-align: center;"&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;&lt;span class="Apple-style-span"  style="font-size:x-small;"&gt;Click Image To Enlarge&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;That yellow branch looks like wycats and carllerche were pairing on a bunch of bug fixes around this time. Notably the two short red arrows I drew here show that they cherry-picked two of those and merged them into the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;2-3-stable&lt;/span&gt; branch. Then, shortly after that, they make a few more fixes that never got merged into the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;2-3-stable&lt;/span&gt; branch. The two I circled in red are the two fixes I mentioned above.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;Completing The Fix&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;I don't know if the Rails team is planning any more updates to the 2.3 line, but if they do release a 2.3.9, I vote for including these two commits, plus the one I applied. So, I forked the repo and created a &lt;a href="http://github.com/scottwb/rails/tree/2-3-cache-fixes"&gt;topic branch&lt;/a&gt; off of &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;2-3-stable&lt;/span&gt; that cherry-picks the two carlhuda commits and includes my additional commit.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;A Workaround&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;Since I'd rather not maintain my own patched version of Rails, for now I am just monkey-patching &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;MemoryStore&lt;/span&gt; and &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ActiveRecord::Base&lt;/span&gt; like so:&lt;br /&gt;&lt;script src="http://gist.github.com/513093.js?file=gistfile1.rb"&gt;&lt;/script&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8917931115554225973-6529204314009074424?l=sleeplesscoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sleeplesscoding.blogspot.com/feeds/6529204314009074424/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8917931115554225973&amp;postID=6529204314009074424&amp;isPopup=true' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/6529204314009074424'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/6529204314009074424'/><link rel='alternate' type='text/html' href='http://sleeplesscoding.blogspot.com/2010/08/rails-23-activesupportcachememorystore.html' title='Rails 2.3 ActiveSupport::Cache::MemoryStore Freezes Objects'/><author><name>scottwb</name><uri>http://www.blogger.com/profile/07534230274246537772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dIGRXKsNGEw/SYiJAKXWsGI/AAAAAAAAABQ/27TDtjQwhfc/S220/mountain01.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_dIGRXKsNGEw/TF3CeBA7_ZI/AAAAAAAAAIg/fOnJGsQODBc/s72-c/The+rails+Network+-+GitHub.png' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8917931115554225973.post-4210405597393754878</id><published>2010-07-05T14:02:00.000-07:00</published><updated>2010-07-05T15:03:08.887-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rubygems'/><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='hacks'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><title type='text'>Install a Rails App's dependencies where 'rake gems:install' fails.</title><content type='html'>&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;Using &lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;rake gems:install&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt; to install the gem dependencies of your Rails 2 app just doesn't seem to work. There are a number of problems you may encounter:&lt;/span&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;&lt;b&gt;Problem 1: It depends on Rails.&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;You have to manually install Rails before you can use &lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;rake gems:install&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;. Ok, so this might not be that big of a deal, but consider this scenario:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style=" ;font-family:'lucida grande';"&gt;Your app is running in production on rails 2.3.4.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style=" ;font-family:'lucida grande';"&gt;You upgrade your app to rails 2.3.5, including the &lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;RAILS_GEM_VERSION&lt;/span&gt;&lt;span class="Apple-style-span"  style=" ;font-family:'lucida grande';"&gt;.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style=" ;font-family:'lucida grande';"&gt;You deploy your app.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;Your deployment script calls &lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;rake gems:install&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt; to keep the dependencies up to date with each new release.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;That fails with something that looks like:&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;script src="http://gist.github.com/464719.js?file=gistfile1.txt"&gt;&lt;/script&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;&lt;b&gt;Problem 2: Sometimes, for some reason, it just doesn't work.&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;Sometimes (most times) you add a new &lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;config.gem&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt; command to &lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;environment.rb&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;. The next deployment runs &lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;rake gems:install&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt; and it fails with the complaint that you are missing the very gem you are hoping it will install for you. For example, in a working Rails 2.3.5 project, add this line to environment.rb:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;blockquote&gt;config.gem 'sanitize', :version =&gt; '1.2.1'&lt;/blockquote&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;Then, run &lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;rake gems:install&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;, and it fails with a "Missing these required gems:" message, e.g.:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;script src="http://gist.github.com/464711.js?file=gistfile1.txt"&gt;&lt;/script&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;WTF? It's telling me to run the command I just ran, to install the missing gem that's preventing that command from running.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;b&gt;Problem 3: It depends on your Rails environment.&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;This can create a circular dependency where some file (particularly vendored plugins/gems) can require a gem to be loaded before the task to install it runs. For example, consider that some file in your &lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;vendor&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt; directory does this:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;blockquote&gt;require 'gdata'&lt;/blockquote&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;Then naturally, you add this to environment.rb:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;blockquote&gt;config.gem 'gdata'&lt;/blockquote&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;The next time you run &lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;rake gems:install&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;, it will fail with a "no such file to load" error, e.g.:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;script src="http://gist.github.com/464717.js?file=gistfile1.txt"&gt;&lt;/script&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;b&gt;The Solution: rails_gem_install&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;I have created a new tool called &lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;rails_gem_install&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt; to help alleviate this problem. Use this instead of &lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;rake gems:install&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;, and you should be much more successful at getting all your Rails app's dependencies installed without manual intervention.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;To install:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;blockquote&gt;gem install rails_gem_install&lt;/blockquote&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;To use:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;cd my_rails_app&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;RAILS_ENV=production rails_gem_install&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;This will install all the gems required to run your app in the production environment, &lt;i&gt;including Rails&lt;/i&gt;. Replace &lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;rake gems:install&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt; in your deployment scripts with &lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;rails_gem_install&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;, and as you change &lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;config.gem&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt; requirements, those gems will be properly installed.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;See the &lt;a href="http://github.com/scottwb/rails_gem_install"&gt;github project page&lt;/a&gt; for more details.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;b&gt;How It Works&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;The main principle behind this tool is that it does not depend on Rails. It creates its own module named Rails that provides some of the functionality from the real Rails that it needs, up until the point that Rails is installed. Then, it only loads some very specific parts of Rails that implement the gem dependency and installation mechanisms, without actually running the app's &lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Rails::Initializer&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt; and loading all of its environment, plugins, etc.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;First, it runs a simple &lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;rake -T&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt; to see if it complains about Rails missing. It parses the output of this, and if necessary, installs the indicated version of Rails.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;Next, it parses out the &lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;config.gem&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt; statements and uses those to ensure all the listed gems requirements are met, and installs those that aren't. It does this without actually loading Rails or the app environment. This carries us most of the way.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;Finally, it runs the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;rake gems&lt;/span&gt; command and parses its output to detect all the kinds of errors described above and install the corresponding gems. This step is repeated until &lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;rake gems&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt; does not complain anymore.&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8917931115554225973-4210405597393754878?l=sleeplesscoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sleeplesscoding.blogspot.com/feeds/4210405597393754878/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8917931115554225973&amp;postID=4210405597393754878&amp;isPopup=true' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/4210405597393754878'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/4210405597393754878'/><link rel='alternate' type='text/html' href='http://sleeplesscoding.blogspot.com/2010/07/install-rails-apps-dependencies-where.html' title='Install a Rails App&apos;s dependencies where &apos;rake gems:install&apos; fails.'/><author><name>scottwb</name><uri>http://www.blogger.com/profile/07534230274246537772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dIGRXKsNGEw/SYiJAKXWsGI/AAAAAAAAABQ/27TDtjQwhfc/S220/mountain01.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8917931115554225973.post-8193118398088895460</id><published>2010-07-01T20:37:00.000-07:00</published><updated>2010-07-01T21:24:56.681-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='CI testing'/><category scheme='http://www.blogger.com/atom/ns#' term='nginx'/><category scheme='http://www.blogger.com/atom/ns#' term='ssl'/><category scheme='http://www.blogger.com/atom/ns#' term='hudson'/><title type='text'>Hudson CI behind an Nginx Reverse Proxy with SSL</title><content type='html'>&lt;div&gt;Here is a quick example nginx configuration to reverse proxy on an HTTPS virtual host to a Hudson CI server running on localhost. When I first tried to do this, the management page displays an error about the configuration being wrong. There are instructions for &lt;a href="http://wiki.hudson-ci.org/display/HUDSON/Running+Hudson+behind+Apache"&gt;Running Hudson behind Apache&lt;/a&gt; that were helpful, and this &lt;a href="http://hudson.361315.n4.nabble.com/Hudson-behind-an-Apache-Reverse-Proxy-w-SSL-td370997.html"&gt;email thread&lt;/a&gt; that seems to suggest terminating SSL at Hudson, not at the reverse proxy. Well, after a bit of tinkering, I worked out this configuration for nginx that worked out great:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/460906.js?file=hudson_nginx.conf"&gt;&lt;/script&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8917931115554225973-8193118398088895460?l=sleeplesscoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sleeplesscoding.blogspot.com/feeds/8193118398088895460/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8917931115554225973&amp;postID=8193118398088895460&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/8193118398088895460'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/8193118398088895460'/><link rel='alternate' type='text/html' href='http://sleeplesscoding.blogspot.com/2010/07/hudson-ci-behind-nginx-reverse-proxy.html' title='Hudson CI behind an Nginx Reverse Proxy with SSL'/><author><name>scottwb</name><uri>http://www.blogger.com/profile/07534230274246537772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dIGRXKsNGEw/SYiJAKXWsGI/AAAAAAAAABQ/27TDtjQwhfc/S220/mountain01.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8917931115554225973.post-2588376454285570654</id><published>2010-04-22T01:37:00.000-07:00</published><updated>2010-04-22T01:44:17.814-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='git'/><category scheme='http://www.blogger.com/atom/ns#' term='shell'/><title type='text'>Find the SHA1 of the latest commit in a git branch</title><content type='html'>Here's a way to get the SHA1 of the last commit in a given branch in a way that can be used in a script easily. For humans &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;`git log branchname`&lt;/span&gt; is probably fine - just read the first line. For a shell script that wants to get that value into a variable, here's a quick way to do that:&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/374977.js?file=get_git_branch_sha.sh"&gt;&lt;/script&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Seems like there ought to be an easier way...but not that I could find in less time than it took to write this command. &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8917931115554225973-2588376454285570654?l=sleeplesscoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sleeplesscoding.blogspot.com/feeds/2588376454285570654/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8917931115554225973&amp;postID=2588376454285570654&amp;isPopup=true' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/2588376454285570654'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/2588376454285570654'/><link rel='alternate' type='text/html' href='http://sleeplesscoding.blogspot.com/2010/04/find-sha1-of-latest-commit-in-git.html' title='Find the SHA1 of the latest commit in a git branch'/><author><name>scottwb</name><uri>http://www.blogger.com/profile/07534230274246537772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dIGRXKsNGEw/SYiJAKXWsGI/AAAAAAAAABQ/27TDtjQwhfc/S220/mountain01.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8917931115554225973.post-2306400986607760292</id><published>2010-04-17T06:23:00.000-07:00</published><updated>2010-04-17T07:30:27.613-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='git'/><title type='text'>GitHub Redemption</title><content type='html'>&lt;div style="text-align: left;"&gt;Moments after posting that last blog post about full directory compare of a git branch, I found out &lt;a href="http://github.com/"&gt;GitHub&lt;/a&gt; supports this already!&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;My post didn't explicitly call out GitHub, because I really think of this mostly as a local working tree issue for me. But, as I went to tweet about it, I realized I would probably be happy enough if GitHub supported something like this, so I called them out in the tweet...and they answered!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Many thanks to Tom Preston-Werner (&lt;a href="http://twitter.com/mojombo"&gt;@mojombo&lt;/a&gt;) for correcting me, and pointing out probably the one link on GitHub I have never clicked: The "Branch List" sub-tab:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;img src="http://3.bp.blogspot.com/_dIGRXKsNGEw/S8m4LkE1PCI/AAAAAAAAAHA/Hh6Cb3gJBJ0/s400/branchlist.png" style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 370px; height: 84px;" border="0" alt="" id="BLOGGER_PHOTO_ID_5461098531965451298" /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I guess I just assumed that it was going to be just a list of all the branches. You know, like &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;`git branch -a`&lt;/span&gt;. So I never clicked on it. Stupid. It turns out it's quite useful.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://1.bp.blogspot.com/_dIGRXKsNGEw/S8m6foZ_RMI/AAAAAAAAAHI/ia-vjbolLv0/s1600/branches.png"&gt;&lt;img src="http://1.bp.blogspot.com/_dIGRXKsNGEw/S8m6foZ_RMI/AAAAAAAAAHI/ia-vjbolLv0/s400/branches.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5461101075748570306" style="display: block; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; text-align: center; cursor: pointer; width: 400px; height: 135px; " /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The stats are pretty cool, but the "Compare" button is what I've been looking for. Clicking that takes you to a page that shows the full directory diff between the head of the branch relative to the "base branch", which in this case is "master". Better yet, it gives you three optio&lt;/div&gt;&lt;div&gt;ns on how to view this diff:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://4.bp.blogspot.com/_dIGRXKsNGEw/S8nBglFC_yI/AAAAAAAAAHQ/1HLiw3WDc84/s1600/compareview.png"&gt;&lt;img src="http://4.bp.blogspot.com/_dIGRXKsNGEw/S8nBglFC_yI/AAAAAAAAAHQ/1HLiw3WDc84/s400/compareview.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5461108788616691490" style="display: block; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; text-align: center; cursor: pointer; width: 400px; height: 59px; " /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;You can see the diffs as a series of commits, the overall file changes (the one I was pining for), or the set of commit comments. This is great. Other than the fact that it doesn't cover&lt;/div&gt;&lt;div&gt; un-pushed commits and uncommitted changes in my local clone, and the fact that I really prefer side-by-side diff format ala &lt;a href="http://www.syntevo.com/smartgit/index.html"&gt;SmartGit&lt;/a&gt; or &lt;a href="http://trac.edgewall.org/"&gt;Trac&lt;/a&gt; (but that's a story for another day), this is pretty much exactly what I wanted -- and if I had known about this 8 hours ago, I probably wouldn't have built the stuff I did.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;But it gets even better. These buttons that show the two branches being compared is clickable.&lt;/div&gt;&lt;div&gt;&lt;a href="http://3.bp.blogspot.com/_dIGRXKsNGEw/S8nEvXMGi1I/AAAAAAAAAHg/hvCkywvy3qU/s1600/branchbuttons.png"&gt;&lt;img src="http://3.bp.blogspot.com/_dIGRXKsNGEw/S8nEvXMGi1I/AAAAAAAAAHg/hvCkywvy3qU/s400/branchbuttons.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5461112341121108818" style="display: block; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; text-align: center; cursor: pointer; width: 164px; height: 39px; " /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;Clicking one of these buttons bring up a modal that allows you to specify a specific commit. This lets you do a full tree diff between any two commits. Awesome!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://2.bp.blogspot.com/_dIGRXKsNGEw/S8nFNHRumLI/AAAAAAAAAHo/MWLTEBMOLcs/s1600/chooseref.png"&gt;&lt;img src="http://2.bp.blogspot.com/_dIGRXKsNGEw/S8nFNHRumLI/AAAAAAAAAHo/MWLTEBMOLcs/s400/chooseref.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5461112852245813426" style="display: block; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; text-align: center; cursor: pointer; width: 400px; height: 260px; " /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In the end, I still think my solution is useful for the case where you want to deal with branches/commits that have not been pushed to GitHub, or you are working in a repository that is not on GitHub. (But who in their right mind does that, right?)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;But, as soon as SmartGit covers this territory, I see no need for my solution...unless you don't use SmartGit (even though you should).&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8917931115554225973-2306400986607760292?l=sleeplesscoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sleeplesscoding.blogspot.com/feeds/2306400986607760292/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8917931115554225973&amp;postID=2306400986607760292&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/2306400986607760292'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/2306400986607760292'/><link rel='alternate' type='text/html' href='http://sleeplesscoding.blogspot.com/2010/04/github-redemption.html' title='GitHub Redemption'/><author><name>scottwb</name><uri>http://www.blogger.com/profile/07534230274246537772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dIGRXKsNGEw/SYiJAKXWsGI/AAAAAAAAABQ/27TDtjQwhfc/S220/mountain01.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_dIGRXKsNGEw/S8m4LkE1PCI/AAAAAAAAAHA/Hh6Cb3gJBJ0/s72-c/branchlist.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8917931115554225973.post-8359969992382989857</id><published>2010-04-17T04:19:00.000-07:00</published><updated>2010-04-17T04:50:36.327-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='git'/><title type='text'>See a visual diff of work done in a git branch with git-branch-diff</title><content type='html'>&lt;div style="text-align: left;"&gt;I have developed a Ruby script called &lt;i&gt;git-branch-diff&lt;/i&gt; that allows you to use a graphical directory compare tool to compare the working tree of a branch with the state of the tree from which it was originally branched. For download, setup, and usage instructons, see:&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;blockquote&gt;&lt;a href="http://github.com/scottwb/git-branch-diff"&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;http://github.com/scottwb/git-branch-diff&lt;/span&gt;&lt;/a&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;Background - My Workflow&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;I don't know about you, but a big part of my development workflow involves constantly diff'ing the changes I have made and am in the progress of making, as a way to constantly keep in touch with the state of what I am working on, and even as a reminder of what I am supposed to be doing. I like to write notes in contextual comments that I never intend to push out to the master branch, to help remind me of TODOs that need to be done before calling a feature sprint done.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In my world of constant multi-tasking and task-switching, I frequently have numerous topic branches in progress on the same repository. I like to end the day with no uncommitted changes, and even no un-pushed changes (i.e.: let github handle backups). So, after a task-switch, it's an integral part of my workflow to be able to see a good diff of the cumulative work I've done in a branch that hasn't been merged back in the master yet. This is usually pretty easy when we're talking about &lt;i&gt;uncommitted&lt;/i&gt; changes. But, when I want to see the set of changes in that branch that would be merged if I were to do it now, things get a little more difficult.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;The Problem&lt;/span&gt;&lt;/div&gt;&lt;div&gt;Git is a powerful tool with a crazy number of features. I probably only know 1% of them...and everywhere I searched, I could not find a way to do a &lt;i&gt;visual directory compare&lt;/i&gt; of what has changed in my branch. Perhaps I've been spoiled by a great line of tools from &lt;a href="http://www.syntevo.com/"&gt;syntevo GmbH&lt;/a&gt; that I've been using for years. I started with &lt;a href="http://www.syntevo.com/smartcvs/index.html"&gt;SmartCVS&lt;/a&gt;, then moved on to &lt;a href="http://www.syntevo.com/smartsvn/index.html"&gt;SmartSVN&lt;/a&gt;, and now to &lt;a href="http://www.syntevo.com/smartgit/index.html"&gt;SmartGit&lt;/a&gt;. I am, always have been, and always will be a command-line guy. I'll admit that most of my cvs/svn/git usage happens from the keyboard. But I have come to rely on these GUI tools as an excellent addition to the command-line when it comes to visualizing my working tree status, performing directory and file diffs, editing line-by-line diffs, 3-way-merge conflict resolution, and easy selective add/commit/revert operations. Over the years I have come to rely on them as a key part of my routine - &lt;b&gt;&lt;i&gt;especially the directory diff view of all the changes in my working tree.&lt;/i&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;SmartGit has that capability for comparing the index, HEAD, and working tree, but not (yet) for arbitrary commits...or what I want most: comparing the HEAD of a topic-branch to the commit from which it was branched. The folks at syntevo assure me this will be included in a forthcoming point release, but what am I to do in the meantime?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Attempted Solution&lt;/span&gt;&lt;/div&gt;&lt;div&gt;I can get the data I want with a command like:&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;git checkout my_topic_branch&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;git diff `git merge-base master HEAD`&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;That shows me exactly the diffs I am interested in, but in a primitive textual (albeit colorized) context diff that I have to navigate with &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;less&lt;/span&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Well, the folks at syntevo have another awesome tool called &lt;a href="http://www.syntevo.com/smartsynchronize/index.html"&gt;SmartSynchronize&lt;/a&gt;. This is their directory/file diff/sync/merge tool from their source control products as a standalone diff tool. So...why not just pump this diff data into that? To do that, you need to edit your &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;~/.gitconfig&lt;/span&gt; file to specify the custom difftool. For example, on Mac OS X, these additions look like:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;script src="http://gist.github.com/369455.js?file=git_config_smartsync"&gt;&lt;/script&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The problem with this is that git invokes the difftool once per file being diff'ed. That's no good. I don't want to open my external visual diff tool 100 times. I want to open it once with a list of all the files added/modified/removed and be able to click on them individually to see their diffs, and ideally even be able to edit, synchronize, revert, etc. SmartSynchronize gives me all this...but git doesn't give it two directories to compare, it gives it two files to compare, one file at a time.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;The Solution&lt;/span&gt;&lt;/div&gt;&lt;div&gt;So, I developed a tool called &lt;i&gt;git-branch-diff&lt;/i&gt; that does all this for me. It works by finding the names and statuses of the differing files and constructing two temporary directories that match the original directory structure with the old and new versions, respectively. Then it passes those directories to SmartSynchronize, and voila! I've got a beautiful directory compare that represents the state of my topic-branch:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://1.bp.blogspot.com/_dIGRXKsNGEw/S8mWsmoXDLI/AAAAAAAAAG4/8CjT9vc_AxQ/s1600/smartsync.png"&gt;&lt;img src="http://1.bp.blogspot.com/_dIGRXKsNGEw/S8mWsmoXDLI/AAAAAAAAAG4/8CjT9vc_AxQ/s400/smartsync.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5461061716191677618" style="display: block; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; text-align: center; cursor: pointer; width: 400px; height: 241px; " /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It only takes a few seconds to download and setup, and using it is as simple as:&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;git checkout my_topic_branch&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;git branch-diff&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;This script would be pretty easy to modify to handle comparing arbitrary commits...but once syntevo adds this to SmartGit, I won't need this anymore anyway! But, for those of you that won't be using SmartGit, this script can still be useful to you, and you can hook it up to whatever directory compare tool you want (e.g.: &lt;a href="http://developer.apple.com/mac/library/documentation/Darwin/Reference/ManPages/man1/opendiff.1.html"&gt;opendiff&lt;/a&gt; or &lt;a href="http://www.scootersoftware.com/"&gt;BeyondCompare&lt;/a&gt;).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you think this tool would be a valuable addition to your workflow, you can get the code and instructions for this tool at:&lt;/div&gt;&lt;div&gt;&lt;a href="http://github.com/scottwb/git-branch-diff"&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;http://github.com/scottwb/git-branch-diff&lt;/span&gt;&lt;/blockquote&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;It can easily plug in any directory compare tool, but I highly recommend you give SmartSynchronize a spin with its 30-day free trial.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;b&gt;NOTE:&lt;/b&gt; One current limitation in this script is that after making and saving modifications in SmartSynchronize, this script does not apply those back to your working tree. I'll probably implement that soon, so if you're interested, stay tuned...&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8917931115554225973-8359969992382989857?l=sleeplesscoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sleeplesscoding.blogspot.com/feeds/8359969992382989857/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8917931115554225973&amp;postID=8359969992382989857&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/8359969992382989857'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/8359969992382989857'/><link rel='alternate' type='text/html' href='http://sleeplesscoding.blogspot.com/2010/04/see-visual-diff-of-work-done-in-git.html' title='See a visual diff of work done in a git branch with git-branch-diff'/><author><name>scottwb</name><uri>http://www.blogger.com/profile/07534230274246537772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dIGRXKsNGEw/SYiJAKXWsGI/AAAAAAAAABQ/27TDtjQwhfc/S220/mountain01.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_dIGRXKsNGEw/S8mWsmoXDLI/AAAAAAAAAG4/8CjT9vc_AxQ/s72-c/smartsync.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8917931115554225973.post-9180207706522493668</id><published>2010-04-17T01:21:00.001-07:00</published><updated>2010-04-17T01:47:05.166-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='hacks'/><category scheme='http://www.blogger.com/atom/ns#' term='haml'/><category scheme='http://www.blogger.com/atom/ns#' term='prototype'/><category scheme='http://www.blogger.com/atom/ns#' term='jQuery'/><title type='text'>How to detect what other sites your visitors have been to</title><content type='html'>When someone visits your site, do you want to know where else they've been? Maybe you want to know if they've been to a competitor or affiliate site so you can make them special offers. Maybe you want to intelligently suggest they signup for your site with Facebook Connect, Twitter, Google OpenID, or Yahoo! ID, based on which of those sites you know they frequent. Maybe you're just nosy.&lt;br /&gt;&lt;br /&gt;Regardless, there are pretty good controls in place with most browser to prevent you from developing javascript on your site that can sniff the user's browser history. There's one small loophole though...you can stick all the URLs you want to know about in your page, and test to see if they have been visited, using the CSS selector features of javascript frameworks such as jQuery and Prototype.js. This is not a fool-proof way to tell where they've been, but it might just be good enough for the kinds of suggestions you want to make to your user.&lt;br /&gt;&lt;br /&gt;Based on ideas from Spyjax (described in this &lt;a href="http://www.merchantos.com/makebeta/tools/spyjax/"&gt;blog post&lt;/a&gt;), I whipped up a simpler demonstration of this using Haml to make a hidden list of URLs and, instead of trying to sniff links by their colors, using Prototype.js to detect which of them have been visited. This could have just as easily been done in jQuery:&lt;br /&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/366373.js?file=gistfile1.haml"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;One extension to this technique, if you have lots of URLs to test, might be to dynamically load 100 at a time via AJAX periodically, and asynchronously trigger actions in your page when visited URLs are detected.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: x-large;"&gt;Isn't that a little creepy? What if I don't want sites to get this info about me?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The Spyjax blog post linked to earlier has a decent answer for this:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;span style="font-style:italic;"&gt;The less browser history you store the fewer URLs someone can steal from that history. In Firefox you can change the amount of browser history by going to Tools -&gt; Options -&gt; Privacy and then either uncheck the “Remember visited pages” checkbox or change the number of days that history is stored for.&lt;/span&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8917931115554225973-9180207706522493668?l=sleeplesscoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sleeplesscoding.blogspot.com/feeds/9180207706522493668/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8917931115554225973&amp;postID=9180207706522493668&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/9180207706522493668'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/9180207706522493668'/><link rel='alternate' type='text/html' href='http://sleeplesscoding.blogspot.com/2010/04/how-to-detect-what-other-sites-your.html' title='How to detect what other sites your visitors have been to'/><author><name>scottwb</name><uri>http://www.blogger.com/profile/07534230274246537772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dIGRXKsNGEw/SYiJAKXWsGI/AAAAAAAAABQ/27TDtjQwhfc/S220/mountain01.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8917931115554225973.post-7590021276644764560</id><published>2010-01-27T00:33:00.000-08:00</published><updated>2010-01-27T00:47:35.087-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='bugs'/><category scheme='http://www.blogger.com/atom/ns#' term='IE'/><category scheme='http://www.blogger.com/atom/ns#' term='DOM'/><category scheme='http://www.blogger.com/atom/ns#' term='jQuery'/><title type='text'>Fixing IE onChange event for checkboxes and radio buttons</title><content type='html'>In Internet Explorer (up to at least IE8) clicking a radio button or checkbox to change its value does not actually trigger the onChange event until the the input loses focus. On every other browser, when the value of the input changes, onChange is triggered.&lt;br /&gt;&lt;br /&gt;This is quite annoying, for example, if you want to trigger some other page changes off of the selection of a radio button in a radio button group changing. Some may suggest using onClick instead, and while that may be sufficient for a checkbox, for radio buttons, this is not a good solution. The problem is that onClick will fire when you click the radio button that is already selected, so you'll get your code triggered even when the value doesn't change.&lt;br /&gt;&lt;br /&gt;Here's a quick hack that worked for me. On IE, handle the onClick event of radio and checkboxes and have it blur and re-focus the input element. This will trigger it to signal the onChange event like you'd expect from a decent browser. Then, you can go about your business using the onChange event like you should, and it will work correctly for you across the popular browsers. (WARNING: Of course, if you have other code triggered off of the blur and focus events, your mileage may vary.)&lt;br /&gt;&lt;br /&gt;Here's an example of how you might do this using jQuery:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="javascript"&gt;&lt;br /&gt;  if ($.browser.msie) {&lt;br /&gt;    $(function() {&lt;br /&gt;      $('input:radio, input:checkbox').click(function() {&lt;br /&gt;        this.blur();&lt;br /&gt;        this.focus();&lt;br /&gt;      });&lt;br /&gt;    });&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8917931115554225973-7590021276644764560?l=sleeplesscoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sleeplesscoding.blogspot.com/feeds/7590021276644764560/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8917931115554225973&amp;postID=7590021276644764560&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/7590021276644764560'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/7590021276644764560'/><link rel='alternate' type='text/html' href='http://sleeplesscoding.blogspot.com/2010/01/fixing-ie-onchange-event-for-checkboxes.html' title='Fixing IE onChange event for checkboxes and radio buttons'/><author><name>scottwb</name><uri>http://www.blogger.com/profile/07534230274246537772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dIGRXKsNGEw/SYiJAKXWsGI/AAAAAAAAABQ/27TDtjQwhfc/S220/mountain01.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8917931115554225973.post-1286797587916474427</id><published>2008-11-30T15:20:00.000-08:00</published><updated>2008-11-30T16:58:37.232-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='haml'/><category scheme='http://www.blogger.com/atom/ns#' term='prototype'/><category scheme='http://www.blogger.com/atom/ns#' term='DRY'/><title type='text'>Sharing a partial for both server-side and client-side HTML generation.</title><content type='html'>Say I have a page that shows a table of items (like a shopping cart), and I want to be able to generate the HTML for this table from the server-side (of course). Let's also say that I want to have client-side javascript be able to dynamically add items to this table without a round-trip to the server, based on data gathered on the client. What I end up with is some HTML code (actually, ERb or Haml) that defines the layout of a row in this table, and a duplicate piece of code in javascript that generates identical HTML. The server-side code uses a nice templating language like Haml to fill in the variable pieces, while the client-side code pieces together HTML embedded in strings concatenated with the dynamic data.&lt;br /&gt;&lt;br /&gt;Not very DRY. Not easy to maintain. Not pretty to look at.&lt;br /&gt;&lt;br /&gt;So...What's a good solution that allows me to write the HTML once, and have one place to maintain it, while still being able to use it to dynamically evaluate the template based on parameterized data on both the server and client sides?&lt;br /&gt;&lt;br /&gt;Below is a solution that I came up with. (And I would love to hear any better ideas).&lt;br /&gt;&lt;br /&gt;For brevity, I'll use a very simple HTML structure in these examples, but in practice I have used this with much more complex structure and logic. Here's what our example table looks like:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="xml"&gt;&lt;br /&gt;&amp;lt;table id="items"&amp;gt;&lt;br /&gt;  &amp;lt;tr&amp;gt;&lt;br /&gt;    &amp;lt;td class="name"&amp;gt;Shirt&amp;lt;/td&amp;gt;&lt;br /&gt;    &amp;lt;td class="desc"&amp;gt;White short-sleeved shirt&amp;lt;/td&amp;gt;&lt;br /&gt;    &amp;lt;td class="price"&amp;gt;$5.99&amp;lt;/td&amp;gt;&lt;br /&gt;  &amp;lt;/tr&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;tr&amp;gt;&lt;br /&gt;    &amp;lt;td class="name"&amp;gt;Pants&amp;lt;/td&amp;gt;&lt;br /&gt;    &amp;lt;td class="desc"&amp;gt;Blue pants with zipper&amp;lt;/td&amp;gt;&lt;br /&gt;    &amp;lt;td class="price"&amp;gt;$25.99&amp;lt;/td&amp;gt;&lt;br /&gt;  &amp;lt;/tr&amp;gt;&lt;br /&gt;&amp;lt;/table&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Assume we have this built using Haml, and there are two partials: one for the top-level table, and one for an individual row. E.g.:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;items_table.haml&lt;/span&gt;:&lt;br /&gt;&lt;pre name="code" class="ruby"&gt;&lt;br /&gt;%table#items&lt;br /&gt;  - items.each do |item|&lt;br /&gt;    = render :partial =&gt; 'item_row', :locals =&gt; {:item =&gt; item}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;item_row.haml&lt;/span&gt;:&lt;br /&gt;&lt;pre name="code" class="ruby"&gt;&lt;br /&gt;%tr&lt;br /&gt;  %td.name= item.name&lt;br /&gt;  %td.desc= item.desc&lt;br /&gt;  %td.price= item.price&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In the client-side javascript in our top-level Haml partial, assume we have some function that gets called from some user input action (like filling out a form and clicking a button). E.g.:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="ruby"&gt;&lt;br /&gt;:javascript&lt;br /&gt;  var addItem = function(name, desc, price) {&lt;br /&gt;    var html =&lt;br /&gt;      "&amp;lt;tr&amp;gt;" +&lt;br /&gt;      "  &amp;lt;td class=\"name\"&amp;gt;" + name + "&amp;lt;/td&amp;gt;" +&lt;br /&gt;      "  &amp;lt;td class=\"desc\"&amp;gt;" + desc + "&amp;lt;/td&amp;gt;" +&lt;br /&gt;      "  &amp;lt;td class=\"price\"&amp;gt;" + price + "&amp;lt;/td&amp;gt;" +&lt;br /&gt;      "&amp;lt;/tr&amp;gt;";&lt;br /&gt;    $('items').insert(html); // using prototype.js&lt;br /&gt;  };&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;OK...so this doesn't seem so bad with such a simple example, but imagine that the HTML structure for a table row is something much more complex, with conditionals based on the item, and maybe even usage of additional sub-partials. This maintenance for this becomes a nightmare.&lt;br /&gt;&lt;br /&gt;This first thing I am going to do is change the &lt;span style="font-family: courier new;"&gt;item_rows.haml&lt;/span&gt; partial. Instead of having it actually render the item's values, it's going to render template replacement variables using &lt;span style="font-family: courier new;"&gt;#{...}&lt;/span&gt; syntax. Note, these are NOT interpolated in the partial. We'll do that in a separate phase from rendering:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;item_row.haml&lt;/span&gt;:&lt;br /&gt;&lt;pre name="code" class="ruby"&gt;&lt;br /&gt;%tr&lt;br /&gt;  %td.name #{item_name}&lt;br /&gt;  %td.desc #{item_desc}&lt;br /&gt;  %td.price #{item_price}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Next, let's make a couple helper methods. The first one returns this partial rendered as a string. (I do this because in the real world, this takes a number of parameters, and adding a helper layer makes things easier to manage than always calling render directly). The second one renders this partial and then interpolates the &lt;span style="font-family: courier new;"&gt;#{...}&lt;/span&gt; strings inside it, based on the properties of the item we want to render -- effectively making this equivalent to rendering the original version of this template.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;item_helper.rb&lt;/span&gt;:&lt;br /&gt;&lt;pre name="code" class="ruby"&gt;&lt;br /&gt;module ItemHelper&lt;br /&gt;  # Make ActionController::Base#render_to_string available.&lt;br /&gt;  helper_method :render_to_string&lt;br /&gt;&lt;br /&gt;  def item_row_template&lt;br /&gt;    render_to_string :partial =&gt; item_row&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  def item_row(item)&lt;br /&gt;    # Get the template.&lt;br /&gt;    t = item_row_template&lt;br /&gt;&lt;br /&gt;    # Define the template replacement variables.&lt;br /&gt;    item_name = item.name&lt;br /&gt;    item_desc = item.desc&lt;br /&gt;    item_price = item.price&lt;br /&gt;&lt;br /&gt;    # Evaluate the template&lt;br /&gt;    eval(t.inspect.gsub("\\#", "#"))&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This, of course, means we change the top-level partial to use this new &lt;span style="font-family: courier new;"&gt;item_row&lt;/span&gt; helper, like so:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;items_table.haml&lt;/span&gt;:&lt;br /&gt;&lt;pre name="code" class="ruby"&gt;&lt;br /&gt;%table#items&lt;br /&gt;  - items.each do |item|&lt;br /&gt;    = item_row(item)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;At this point, we've got a functionally equivalent server-side. But the big benefit is that now the HTML template returned by the &lt;span style="font-family: courier new;"&gt;item_row_template&lt;/span&gt; helper method can also be used to do the same substitutions on the client side, thanks to the handy &lt;a href="http://www.prototypejs.org/api/template"&gt;Template&lt;/a&gt; class in &lt;a href="http://www.prototypejs.org/"&gt;prototype.js&lt;/a&gt;. The Haml that defines the javascript &lt;span style="font-family: courier new;"&gt;addItem&lt;/span&gt; method now looks like this:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="ruby"&gt;&lt;br /&gt;:javascript&lt;br /&gt;  var addItem = function(name, desc, price) {&lt;br /&gt;    var html = new Template(&lt;br /&gt;      '#{escape_javascript(item_row_template)}'&lt;br /&gt;    ).evaluate({&lt;br /&gt;      item_name : name,&lt;br /&gt;      item_desc : desc,&lt;br /&gt;      item_price : price&lt;br /&gt;    });&lt;br /&gt;    $('items').insert(html);&lt;br /&gt;  };&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now, when the markup for the item row changes, it only needs to change in one place, and both the server-side and client-side benefit from it. This certainly feels more DRY...but also seems like a hefty price to pay in terms of complexity...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8917931115554225973-1286797587916474427?l=sleeplesscoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sleeplesscoding.blogspot.com/feeds/1286797587916474427/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8917931115554225973&amp;postID=1286797587916474427&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/1286797587916474427'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/1286797587916474427'/><link rel='alternate' type='text/html' href='http://sleeplesscoding.blogspot.com/2008/11/sharing-partial-for-both-server-side.html' title='Sharing a partial for both server-side and client-side HTML generation.'/><author><name>scottwb</name><uri>http://www.blogger.com/profile/07534230274246537772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dIGRXKsNGEw/SYiJAKXWsGI/AAAAAAAAABQ/27TDtjQwhfc/S220/mountain01.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8917931115554225973.post-5536922610996515347</id><published>2008-11-17T15:45:00.000-08:00</published><updated>2008-11-17T16:12:25.860-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='bugs'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='haml'/><category scheme='http://www.blogger.com/atom/ns#' term='rhtml'/><title type='text'>Bug in Haml Partial Rendering?</title><content type='html'>I have stumbled across what I think is a bug in rendering a Haml partial in Ruby on Rails. The issue is that when I use &lt;span style="font-family: courier new;"&gt;render(:partial =&gt; '...', :locals =&gt; {...})&lt;/span&gt;, and one of the locals I define is a &lt;span style="font-family: courier new;"&gt;Boolean&lt;/span&gt;, it seems that if I pass a value of &lt;span style="font-family: courier new;"&gt;false&lt;/span&gt;, that value erroneously gets converted to &lt;span style="font-family: courier new;"&gt;nil&lt;/span&gt;. This causes a problem with a partial that wants to treat &lt;span style="font-family: courier new;"&gt;false&lt;/span&gt;, &lt;span style="font-family: courier new;"&gt;true&lt;/span&gt;, and &lt;span style="font-family: courier new;"&gt;nil&lt;/span&gt; as meaning different things.&lt;br /&gt;&lt;br /&gt;Consider the following example:&lt;br /&gt;&lt;br /&gt;I have a simple TestController:&lt;br /&gt;&lt;pre name="code" class="ruby"&gt;&lt;br /&gt;class TestController &lt; ApplicationController&lt;br /&gt;  def index&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Then, the haml template for that controller:&lt;br /&gt;&lt;pre name="code" class="ruby"&gt;&lt;br /&gt;!!!&lt;br /&gt;%html&lt;br /&gt;  %head&lt;br /&gt;    %title haml partial test&lt;br /&gt;  %body&lt;br /&gt;    %b Rendering a Haml Partial&lt;br /&gt;    %br&lt;br /&gt;    = render :partial =&gt; 'test_haml', :locals =&gt; {:flag1 =&gt; true, :flag2 =&gt; false}&lt;br /&gt;&lt;br /&gt;    %hr&lt;br /&gt;    %b Rendering an RHTML Partial&lt;br /&gt;    %br&lt;br /&gt;    = render :partial =&gt; 'test_rhtml', :locals =&gt; {:flag1 =&gt; true, :flag2 =&gt; false}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Notice that partial renders two partials. One is a haml partial, one is an rhtml partial. The rthml one behaves as I would expect, the haml one does not.&lt;br /&gt;&lt;br /&gt;Here is what the haml partial looks like:&lt;br /&gt;&lt;pre name="code" class="ruby"&gt;&lt;br /&gt;- if flag1 == false&lt;br /&gt;  flag1 is false&lt;br /&gt;- elsif flag1 == true&lt;br /&gt;  flag1 is true&lt;br /&gt;- elsif flag1 == nil&lt;br /&gt;  flag1 is nil&lt;br /&gt;- else&lt;br /&gt;  = "flag1 is #{flag1.inspect}"&lt;br /&gt;&lt;br /&gt;%br&lt;br /&gt;%br&lt;br /&gt;&lt;br /&gt;- if flag2 == false&lt;br /&gt;  flag2 is false&lt;br /&gt;- elsif flag2 == true&lt;br /&gt;  flag2 is true&lt;br /&gt;- elsif flag2 == nil&lt;br /&gt;  flag2 is nil&lt;br /&gt;- else&lt;br /&gt;  = "flag2 is #{flag2.inspect}"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Here is what the rhtml partial looks like:&lt;br /&gt;&lt;pre name="code" class="ruby"&gt;&lt;br /&gt;&lt;% if flag1 == false %&gt;&lt;br /&gt;  flag1 is false&lt;br /&gt;&lt;% elsif flag1 == true %&gt;&lt;br /&gt;  flag1 is true&lt;br /&gt;&lt;% elsif flag1 == nil %&gt;&lt;br /&gt;  flag1 is nil&lt;br /&gt;&lt;% else %&gt;&lt;br /&gt;  flag1 is &lt;%= flag1.inspect %&gt;&lt;br /&gt;&lt;% end %&gt;&lt;br /&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;&lt;br /&gt;&lt;% if flag2 == false %&gt;&lt;br /&gt;  flag2 is false&lt;br /&gt;&lt;% elsif flag2 == true %&gt;&lt;br /&gt;  flag2 is true&lt;br /&gt;&lt;% elsif flag2 == nil %&gt;&lt;br /&gt;  flag2 is nil&lt;br /&gt;&lt;% else %&gt;&lt;br /&gt;  flag2 is &lt;%= flag2.inspect %&gt;&lt;br /&gt;&lt;% end %&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Here is what the output looks like:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_dIGRXKsNGEw/SSIIJ0tz2mI/AAAAAAAAABI/92EtfkCXoI4/s1600-h/haml_partial_test.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 237px; height: 175px;" src="http://3.bp.blogspot.com/_dIGRXKsNGEw/SSIIJ0tz2mI/AAAAAAAAABI/92EtfkCXoI4/s320/haml_partial_test.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5269783478839532130" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Notice the discrepancy between the output of the haml partial versus the rhtml partial, with respect to &lt;span style="font-family: courier new;"&gt;flag2&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;This is gonna turn out to be a real drag on a project that I am converting from rhtml to haml that has a number of partials that assume that &lt;span style="font-family: courier new;"&gt;false&lt;/span&gt; means &lt;span style="font-family: courier new;"&gt;false&lt;/span&gt; and not &lt;span style="font-family: courier new;"&gt;nil&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Anybody out there have any thoughts on this?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8917931115554225973-5536922610996515347?l=sleeplesscoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sleeplesscoding.blogspot.com/feeds/5536922610996515347/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8917931115554225973&amp;postID=5536922610996515347&amp;isPopup=true' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/5536922610996515347'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/5536922610996515347'/><link rel='alternate' type='text/html' href='http://sleeplesscoding.blogspot.com/2008/11/bug-in-haml-partial-rendering.html' title='Bug in Haml Partial Rendering?'/><author><name>scottwb</name><uri>http://www.blogger.com/profile/07534230274246537772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dIGRXKsNGEw/SYiJAKXWsGI/AAAAAAAAABQ/27TDtjQwhfc/S220/mountain01.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_dIGRXKsNGEw/SSIIJ0tz2mI/AAAAAAAAABI/92EtfkCXoI4/s72-c/haml_partial_test.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8917931115554225973.post-1998838387434409830</id><published>2008-10-12T01:14:00.000-07:00</published><updated>2008-10-12T03:56:23.542-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='blogger'/><category scheme='http://www.blogger.com/atom/ns#' term='google sites'/><category scheme='http://www.blogger.com/atom/ns#' term='syntax highlighting'/><title type='text'>Blogger Syntax Highlighting</title><content type='html'>Since I intend to post code snippets here, I guess I had better figure out how to format code nicely in my blog. I am using Blogger, and from what I can tell in my vast 2 hours of Blogger experience, they don't have any simple built-in way to do nice code formatting and syntax highlighting.&lt;br /&gt;&lt;br /&gt;I found a lot of references on how to use the very cool &lt;a href="http://code.google.com/p/syntaxhighlighter/"&gt;SyntaxHighlighter&lt;/a&gt;. Check out blogs on this topic from &lt;a href="http://developertips.blogspot.com/2007/08/syntaxhighlighter-on-blogger.html"&gt;developertips&lt;/a&gt; and &lt;a href="http://ideamonk.blogspot.com/2008/06/adding-syntaxhighlighter-to-your.html"&gt;IdeaMonk&lt;/a&gt; -- that stuff helped a lot.&lt;br /&gt;&lt;br /&gt;However, I think since these posts, the javascript code they describe to fix Blogger-specific issues with automatically-inserted &lt;tt&gt;&amp;lt;br/&amp;gt;&lt;/tt&gt; tags has been rolled into the SyntaxHighlighter code, or is otherwise no longer necessary. Including it seems to break the formatting on my blog -- it was removing too many line breaks and putting all my code on one line. I didn't really dig into why that was the case. I just noticed that by removing the extra javascript code and adding the &lt;tt&gt;BloggerMode()&lt;/tt&gt; call, everything worked out nicely.&lt;br /&gt;&lt;br /&gt;So...here's a step-by-step walk-through of what I did to get this working:&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Step 1: Get SyntaxHighlighter&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Download the latest version of &lt;a href="http://syntaxhighlighter.googlecode.com/files/SyntaxHighlighter_1.5.1.rar"&gt;SyntaxHighlighter&lt;/a&gt; (1.5.1 as of this writing).&lt;/li&gt;&lt;li&gt;Uncompress the RAR file (&lt;a href="http://www.rarlab.com/download.htm"&gt;download WinRar&lt;/a&gt; if necessary).&lt;/li&gt;&lt;li&gt;Place the contents of the &lt;tt&gt;scripts&lt;/tt&gt; and &lt;tt&gt;styles&lt;/tt&gt; directories onto a web server that can serve these files for your blog (more on that later). I put these files all in a flat directory structure in my example.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h3&gt;Step 2: Add SyntaxHighlighter to your template&lt;/h3&gt;On Blogger, go to &lt;span style="font-weight: bold;"&gt;Layout-&gt;Edit HTML&lt;/span&gt; and add the following code to your template, just before the &lt;tt&gt;&amp;lt;/head&amp;gt;&lt;/tt&gt; closing tag:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="Jscript"&gt;&lt;br /&gt;&amp;lt;link href="http://[YOURSITE]/SyntaxHighlighter.css" rel="stylesheet" type="text/css"/&amp;gt;&lt;br /&gt;&amp;lt;script src="http://[YOURSITE]/shCore.js" type="text/javascript"/&amp;gt;&lt;br /&gt;&amp;lt;script src="http://[YOURSITE]/shBrushCpp.js" type="text/javascript"/&amp;gt;&lt;br /&gt;&amp;lt;script src="http://[YOURSITE]/shBrushCSharp.js" type="text/javascript"/&amp;gt;&lt;br /&gt;&amp;lt;script src="http://[YOURSITE]/shBrushCss.js" type="text/javascript"/&amp;gt;&lt;br /&gt;&amp;lt;script src="http://[YOURSITE]/shBrushDelphi.js" type="text/javascript"/&amp;gt;&lt;br /&gt;&amp;lt;script src="http://[YOURSITE]/shBrushJava.js" type="text/javascript"/&amp;gt;&lt;br /&gt;&amp;lt;script src="http://[YOURSITE]/shBrushJScript.js" type="text/javascript"/&amp;gt;&lt;br /&gt;&amp;lt;script src="http://[YOURSITE]/shBrushPhp.js" type="text/javascript"/&amp;gt;&lt;br /&gt;&amp;lt;script src="http://[YOURSITE]/shBrushPython.js" type="text/javascript"/&amp;gt;&lt;br /&gt;&amp;lt;script src="http://[YOURSITE]/shBrushRuby.js" type="text/javascript"/&amp;gt;&lt;br /&gt;&amp;lt;script src="http://[YOURSITE]/shBrushSql.js" type="text/javascript"/&amp;gt;&lt;br /&gt;&amp;lt;script src="http://[YOURSITE]/shBrushVb.js" type="text/javascript"/&amp;gt;&lt;br /&gt;&amp;lt;script src="http://[YOURSITE]/shBrushXml.js" type="text/javascript"/&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;(You can delete the lines for languages you aren't going to use.)&lt;br /&gt;&lt;br /&gt;Then, at the bottom of your template, just before the &lt;tt&gt;&amp;lt;/body&amp;gt;&lt;/tt&gt; closing tag, add the following code:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="Jscript"&gt;&lt;br /&gt;&amp;lt;script type="text/javascript"&amp;gt;&lt;br /&gt;//&amp;lt;![CDATA[&lt;br /&gt;dp.SyntaxHighlighter.ClipboardSwf = "http://[YOURSITE]/clipboard.swf";&lt;br /&gt;dp.SyntaxHighlighter.BloggerMode();&lt;br /&gt;dp.SyntaxHighlighter.HighlightAll("code");&lt;br /&gt;//]]&amp;gt;&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Step 3: Markup your code snippets&lt;/h3&gt;Anywhere you want to stick a piece of code in your blog, put code like:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="Jscript"&gt;&lt;br /&gt;&amp;lt;pre name="code" class="ruby"&amp;gt;&lt;br /&gt;  class Foo&lt;br /&gt;    def bar&lt;br /&gt;      puts "foo bar"&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;That should give you something that looks like:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="ruby"&gt;&lt;br /&gt;class Foo&lt;br /&gt;  def bar&lt;br /&gt;    puts "foo bar"&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The name of the class you use specifies what language to format the code as, and directly corresponds to the names of those javascript files you included in your template.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;What if I don't have a web server for these files?&lt;/h3&gt;Unfortunately, as far as I can tell, Blogger doesn't provide any static file storage that you can use to serve up these files. (It sure would be nice if they had them already installed somewhere we could all pull them from.) For a quick-and-dirty, free solution that I am not really happy with, try &lt;a href="http://sites.google.com/"&gt;Google Sites&lt;/a&gt;. There is one catch: they don't let you store &lt;tt&gt;.js&lt;/tt&gt; files. Here's what I did with Google Sites:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Create a new account and a new site.&lt;/li&gt;&lt;li&gt;Once you're in, create a new page called "SyntaxHighlighter", that is a "File Cabinet".&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Rename all the .js files to end in .sj instead.&lt;/li&gt;&lt;li&gt;Update the .css file and all the .sj files to this new file cabinet.&lt;/li&gt;&lt;li&gt;Modify all the code in your Blogger template that points to these .js files to end in .sj.&lt;/li&gt;&lt;li&gt;From the Google Sites file cabinet, copy the link location to one of the files and use the relevant part of that to fix up all the css and js links in your template.&lt;/li&gt;&lt;/ul&gt;The main caveat to this approach is that it seems to be really slow. I am using the nice friendly URLs to the files on Google Sites, which all end up using HTTP redirects. It's less than ideal, but it's also quick to setup and free. Once you like the way this stuff works on your blog, you can probably find a better place to host those css and js files.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Caveats&lt;/h3&gt;&lt;br /&gt;I still have a couple issues that I didn't spend any time figuring out yet:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;  &lt;li&gt;I think if you go back and forth between "Edit Html" mode and "Compose" mode, you may get extra &lt;tt&gt;&amp;lt;br/&amp;gt;&lt;/tt&gt; tags inserted into your code.&lt;br /&gt;  &lt;li&gt;This seemed to mess up the drag-n-drop layout editor. As far as I can tell, it only messed up the placement of the gadgets in the layout editor, but not the actual functionality, and the gadgets still appear on the blog posts in the correct place.&lt;br /&gt;  &lt;li&gt;The SyntaxHighlighter, or at least the way I added it to my template, seems to break on IE6. It's way too late to care about IE6 users. Those people don't deserve to suck any more time from web developers than they already have.&lt;br /&gt;  &lt;li&gt;Shit. I just found out it's broken on Safari too. Looks like its "too many redirects" for the ".sj" files. I am thinking that hosting these files on Google Sites is not such a good idea...&lt;br /&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8917931115554225973-1998838387434409830?l=sleeplesscoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sleeplesscoding.blogspot.com/feeds/1998838387434409830/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8917931115554225973&amp;postID=1998838387434409830&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/1998838387434409830'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/1998838387434409830'/><link rel='alternate' type='text/html' href='http://sleeplesscoding.blogspot.com/2008/10/blogger-syntax-highlighting.html' title='Blogger Syntax Highlighting'/><author><name>scottwb</name><uri>http://www.blogger.com/profile/07534230274246537772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dIGRXKsNGEw/SYiJAKXWsGI/AAAAAAAAABQ/27TDtjQwhfc/S220/mountain01.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8917931115554225973.post-7078321630929666249</id><published>2008-10-11T12:01:00.000-07:00</published><updated>2008-10-11T13:38:48.427-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sleep'/><category scheme='http://www.blogger.com/atom/ns#' term='blogging'/><title type='text'>I Can't Sleep</title><content type='html'>I can't sleep. Granted, it's noon on a Saturday and I am not supposed to be sleeping, but I don't mean right this minute...I mean most nights. I have hundreds of thoughts running through my head laying in bed...usually about code of some sort. Most times when this happens, I get up and start coding. Usually for work, but often just messing around for fun. I have been told many times that I should start a blog, post code snippets, talk about interesting new things I am playing around with, etc.  Yeah...I am years and years behind the curve on this -- mainly because I prefer coding to talking about coding. But alas, I have decided to try my hand at blogging a little bit about the stuff I am toying around with, so here goes...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8917931115554225973-7078321630929666249?l=sleeplesscoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sleeplesscoding.blogspot.com/feeds/7078321630929666249/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8917931115554225973&amp;postID=7078321630929666249&amp;isPopup=true' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/7078321630929666249'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8917931115554225973/posts/default/7078321630929666249'/><link rel='alternate' type='text/html' href='http://sleeplesscoding.blogspot.com/2008/10/i-cant-sleep.html' title='I Can&apos;t Sleep'/><author><name>scottwb</name><uri>http://www.blogger.com/profile/07534230274246537772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_dIGRXKsNGEw/SYiJAKXWsGI/AAAAAAAAABQ/27TDtjQwhfc/S220/mountain01.jpg'/></author><thr:total>2</thr:total></entry></feed>
