<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Rails Monkey</title>
	<atom:link href="http://railsmonkey.net/feed/" rel="self" type="application/rss+xml" />
	<link>http://railsmonkey.net</link>
	<description>&#039;cause Rails rocks, and everything is better with a monkey... ;)</description>
	<lastBuildDate>Thu, 11 Aug 2011 07:41:05 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Deploying Rails 3.1 applications with Capistrano</title>
		<link>http://railsmonkey.net/2011/08/deploying-rails-3-1-applications-with-capistrano/</link>
		<comments>http://railsmonkey.net/2011/08/deploying-rails-3-1-applications-with-capistrano/#comments</comments>
		<pubDate>Thu, 11 Aug 2011 07:41:05 +0000</pubDate>
		<dc:creator>Matthew Savage</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[asset pipeline]]></category>
		<category><![CDATA[capistrano]]></category>
		<category><![CDATA[deploy]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[rails 3.1]]></category>

		<guid isPermaLink="false">http://railsmonkey.net/?p=399</guid>
		<description><![CDATA[I&#8217;m currently working on an application using the latest RC of Rails 3.1 (rc5, which is actually quite stable). In [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m currently working on an application using the latest RC of <a href="http://weblog.rubyonrails.org/2011/5/22/rails-3-1-release-candidate" title="Rails 3.1" target="_blank">Rails 3.1</a> (rc5, which is actually quite stable). In Rails 3.1 there is a new <a href="http://ryanbigg.com/guides/asset_pipeline.html" title="Asset Pipeline" target="_blank">Asset Pipeline</a> which now handles images, stylesheets, javascripts etc differently, especially when it comes to the filename.</p>
<p>In a Rails 3.0 or Rails 2.3 app, by default, a cache busting parameter is appended to the resource URL, for example: http://www.something.com/images/monkeys.jpg?138767865 &#8211; this number appended to the end if the mtime of the file from that server. When this was first put into place this was great, it worked as prescribed and was easy to manage, however there are some&nbsp;behaviours&nbsp;which this technique brings along with it:</p>
<ul>
<li>Some caching servers will not cache a URL with a query string</li>
<li>The mtime of the file would be different across a web cluster, so you would have conflicting URLs and the cache wouldn&#8217;t work as expected</li>
</ul>
<div>With the Rails 3.1 Asset Pipeline the files are now named with a hash in their file name, so <strong>monkeys.jpg</strong>&nbsp;becomes <strong>monkeys-bec6c752b4e7fbfa9ee4b99b562a03ca.png</strong>.</div>
<div>This, like the previous technique, comes for free in terms of configuration in the application, how you reference an image etc*, however when you deploy there is a rake task you should run to generate these files, which is <strong>rake assets:precompile</strong>.</div>
<div>So, how do you make this happen all by magic? Well I use <a href="http://www.capify.org" title="Capistrano" target="_blank">Capistrano</a> for deployment, so all I really need to do it make it call the rake tasks after deploying. You can easily do the same by adding the following code to the bottom of your deploy.rb file:</div>
<pre class="brush:ruby">
namespace :assets do
  task :precompile, :roles =&gt; :web do
    run "cd #{current_path} &amp;&amp; RAILS_ENV=production bundle exec rake assets:precompile"
  end

  task :cleanup, :roles =&gt; :web do
    run "cd #{current_path} &amp;&amp; RAILS_ENV=production bundle exec rake assets:clean"
  end
end

after :deploy, "assets:precompile"
</pre>
<p>There is also a cleanup task included to get rid of any hanging around assets which aren&#8217;t being used any more which you can run by calling <strong>cap assets:cleanup</strong>.</p>
<p>Hope this helps.</p>
<p>* There is one caveat, and that is with images referenced in CSS &#8211; if you are using SASS you can use <code>image-url(...)</code> which will output a <code>url(...)</code> directive with the correct URL, however in plain old CSS you should use <code>url('<%= asset_path(...) %>');</code> and name the file with the .erb prefix to be preprocessed.</p>
]]></content:encoded>
			<wfw:commentRss>http://railsmonkey.net/2011/08/deploying-rails-3-1-applications-with-capistrano/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Problems logging in to Snow Leopard domain after install OS X Lion</title>
		<link>http://railsmonkey.net/2011/07/problems-logging-in-to-snow-leopard-domain-after-install-os-x-lion/</link>
		<comments>http://railsmonkey.net/2011/07/problems-logging-in-to-snow-leopard-domain-after-install-os-x-lion/#comments</comments>
		<pubDate>Sun, 24 Jul 2011 11:20:10 +0000</pubDate>
		<dc:creator>Matthew Savage</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[IT Consulting]]></category>
		<category><![CDATA[User Experience]]></category>
		<category><![CDATA[lion]]></category>
		<category><![CDATA[osx]]></category>
		<category><![CDATA[snow leopard]]></category>
		<category><![CDATA[upgrdes]]></category>

		<guid isPermaLink="false">http://railsmonkey.net/?p=381</guid>
		<description><![CDATA[TL;DR Just installed Lion and can&#8217;t log in? Boot into recovery, open terminal, enter resetpassword, reset root password, reboot, login [...]]]></description>
			<content:encoded><![CDATA[<p><strong>TL;DR</strong></p>
<p><strong></strong>Just installed Lion and can&#8217;t log in? Boot into recovery, open terminal, enter <strong>resetpassword</strong>, reset root password, reboot, login as root, rebind to Open Directory, reboot, profit <img src='http://railsmonkey.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p><strong>The Long Story</strong></p>
<p>I received a phone call on Friday from someone who made the decision to update to <a title="OS X Lion" href="http://www.apple.com/macosx/" target="_blank">OS X Lion</a>, and ran into a huge problem &#8211; unable to log into the computer&#8230; at all. In normal circumstances this wouldn&#8217;t be an issue, I would just have the user log in with a local account, however as this was a system which was bound to an Open Directory server on an OS X Snow Leopard server, and during the setup a local-only account was not setup.</p>
<p>When I looked into the issue there was some errors popping up in the Open Directory password service, mainly:</p>
<pre>'username' DIGEST-MD5 authentication failed, SASL error -13</pre>
<p>Now, this to me normally indicates there&#8217;s an issue between the client computer and the server with the <a title="Kerberos Protocol" href="http://en.wikipedia.org/wiki/Kerberos_(protocol)" target="_blank">Kerberos</a> authentication, i.e. possibly an issue with the shared secret or similar &#8211; especially considering that the users password hadn&#8217;t changed, and the user was able to log into another machine without any issues.</p>
<p>Now, the solution, was actually somewhat simple. OS X Lion now sets up a <a title="About Lion Recovery" href="http://support.apple.com/kb/HT4718" target="_blank">Recovery Partition</a> which you can access by booting while holding Command + R, or holding down the Option key and choosing the <a title="Accessing the recovery partition" href="http://reviews.cnet.co.uk/software-and-web-apps/how-to-recover-os-x-lion-50004503/" target="_blank">Recovery HD</a> from the options.</p>
<p>Once you have booted into the Recovery Partition there is a menu titled <strong>Utilities</strong> - click that and choose <strong>Terminal</strong>, which will bring up the lovely world of the OS X Terminal, and thankfully there is one single command you need to enter: <strong>resetpassword</strong></p>
<p>Entering this magical command will bring up a dialog asking you to choose which account you want to reset the password for &#8211; choose the <strong>root</strong> account, and then enter a password of your choosing, then simply reboot your computer.</p>
<p>Once you have rebooted you can then login as the <strong>root</strong> user, by selecting &#8216;other user&#8217; and typing in the username and password &#8211; now you are logged in as an administrator account which will allow for you to recovery your login (hint: rename your account, including the login, maybe back up your data, then kind of create a new account and move the data back).</p>
<p>If your issue relates to the binding with Open Directory the solution is quite straight forward &#8211; in System Preferences, under Users &amp; Accounts/Login Options edit the Open Directory bindings and remove your current one, then re-join the directory (you may want to remove the machine account from the directory in between these two steps). Once done simply reboot and you should be able to log in to your account again &#8211; woo hoo!</p>
<p>Good luck!</p>
<p>Footnote: this probably doesn&#8217;t need to be said, but don&#8217;t forget to back up your system <strong>before</strong> installing Lion &#8211; it will save you a world of trouble and panic.</p>
]]></content:encoded>
			<wfw:commentRss>http://railsmonkey.net/2011/07/problems-logging-in-to-snow-leopard-domain-after-install-os-x-lion/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>On procrastination</title>
		<link>http://railsmonkey.net/2011/05/on-procrastination/</link>
		<comments>http://railsmonkey.net/2011/05/on-procrastination/#comments</comments>
		<pubDate>Sat, 28 May 2011 13:05:42 +0000</pubDate>
		<dc:creator>Matthew Savage</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Motivation]]></category>

		<guid isPermaLink="false">http://railsmonkey.net/?p=380</guid>
		<description><![CDATA[I&#8217;ve traveled for work a fair bit over the past three months &#8211; my job has seen me ending up [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve traveled for work a fair bit over the past three months &#8211; my job has seen me ending up in New Zealand (<a title="Auckland, NZ" href="http://www.aucklandnz.com/" target="_blank">Auckland</a> &amp; <a title="Gisbourne, NZ" href="http://www.gisbornenz.com/" target="_blank">Gisbourne</a>), Scotland (<a title="Thurso, Scotland" href="http://www.undiscoveredscotland.co.uk/thurso/thurso/index.html" target="_blank">Thurso</a>, via <a title="Edinburgh" href="http://www.edinburgh.org/" target="_blank">Edinburgh</a>, and then back to <a title="London" href="http://www.visitlondon.com/" target="_blank">London</a> for 2 days off) and in <a title="Sydney" href="http://www.sydney.com.au/" target="_blank">Sydney</a> for a week around <a title="Dee Why" href="http://www.dyslsc.org.au/" target="_blank">Dee Why</a>. While I&#8217;ve been away for work I was hoping for some time to multitask &#8211; while my main requirement on site has been satisfied (i.e. everything is running smoothly, as expected etc) I had expected to be able to work on other projects, perhaps one specific project which is a little over-due.</p>
<p>Unfortunately this wasn&#8217;t how it played out&#8230;</p>
<p>I suppose our best laid plans don&#8217;t always happen as we expect them to, and in my case it was no different. However part of this was myself allowing minor hurdles stopping me from doing the work I had originally intended to do.</p>
<h3>A bit of background</h3>
<p>Let me paint the picture for you a bit &#8211; I am, as my main vocation, a software developer. Currently I work full-time for a company based in Sydney, but from my cosy apartment in Canberra. This company is based deeply in the surfing industry, and as a result we&#8217;re somewhat in events that pop up, mainly within the broadcasting side of things.</p>
<p>Remembering what I do daily &#8211; my position in these events is the <strong>broadcast technician</strong> &#8211; at the end of the day a fancy pants word for:</p>
<ul>
<li>Setting up the webcast encoder</li>
<li>Setting up the webcast internet connection (and this varies from ADSL connections, 3G connections, a satellite connection &#8211; whatever it is, its my domain)</li>
<li>Setting up the audio mixer and tuning the levels on the Microphones and other inputs</li>
<li>Setting up the production mixing desk, video playout system, camera sources etc</li>
<li>Making sure everything plays nicely together</li>
<li>Ensuring those who need it can get access to the internet (this, believe me, is a huge problem up in Thurso&#8230;)</li>
<li>then when all that is up and running and no one is panicking&#8230; panicking over the things which need to be fixed and educating the runners</li>
<li>when required, be a runner &#8211; at a last resort</li>
</ul>
<p>I&#8217;m not complaining about this though &#8211; working on the events is such an amazing experience. Normally I am not a morning person but when you get into these things where you&#8217;re up at 5am, finishing off at 9pm, rinse and repeat&#8230; its challenging but amazing.</p>
<h3>But&#8230;</h3>
<p>My expectations on how often I would be required, interrupted, etc &#8211; completely underestimated. Here I was imagining that I would get everything up and running, then be able to sit down and bash out some code until the next situation &#8211; and perhaps I could have.</p>
<p>Unfortunately I fell into the trap of laziness and things would pop up which I allowed to make it &#8216;hard&#8217; to work on things. And these weren&#8217;t necessarily small things either &#8211; something like &#8220;oh the internet connection is unstable, so I can&#8217;t drop stories into Pivotal&#8221; or &#8220;I am not able to find a comfortable place where I won&#8217;t be interrupted, so&#8230;.&#8221;. In hindsight its relatively pathetic.</p>
<h3>The moral?</h3>
<p>I&#8217;m (hopefully) not just blubbering uselessly about my trials and tribulations, I promise &#8211; there is a &#8216;moral to this story&#8217;. Recently I sat down with a business partner and discussed how I &#8220;didn&#8217;t have time to work on this project&#8221; &#8211; which was not only disappointing to my business partner, because he&#8217;s depending on me to deliver something, but it was also disappointing to me, because I was letting my friend down.</p>
<p>During our discussion we decided to setup a bit of a mind trick to get some work churned out. Originally I would say something like &#8220;Oh let me work on this tonight and I&#8217;ll come back to you in a day or two with it&#8230;&#8221; and lo and behold, I never delivered&#8230; When I was looking back on some things I had read by the guys at <a title="37signals" href="http://www.37signals.com" target="_blank">37signals</a> (in their book <a title="Getting Real" href="http://gettingreal.37signals.com/" target="_blank">Getting Real</a> &#8211; <em>not an affiliate link, but the book, it rocks!</em>) I remembered what DHH had said about his limited time while working on Basecamp &#8211; <a title="It doesn't have to be all or nothing with a startup" href="http://37signals.com/svn/posts/1078-it-doesnt-have-to-be-all-or-nothing-with-a-startup" target="_blank">10 hours per week</a>, plus there was a time difference from the office being in Chicago and DHH being in Denmark.</p>
<p>With this in mind I decided to try something out &#8211; I had already had good experience working in sprints of 25 to 30 minutes, then taking a break, then starting again, so with my business partner we agreed to try something similar. Each day, for 1 hour, we sit down together and bash out some work. It doesn&#8217;t have to be perfect, in reality it could change the very next day, but the main thing is that we were making progress &#8211; taking that step forward required to gain momentum.</p>
<h3>Has it worked?</h3>
<p>So far, yes. There have been days, due to appointments etc, where we haven&#8217;t been able to meet as agreed, however most of the time we accomplish what we have aimed for and the progress is a good feeling. I still have issues with the procrastination bug at times, but at the end of the day there really is a reason why we procrastinate.</p>
<p>Looking back at the times I was away I could have easily done the &#8216;work&#8217; I had intended to do while I was away. The reasons seem pitiful:</p>
<ul>
<li>I can&#8217;t get a stable internet connection &#8211; <em>just pick something to work on and churn out some code. If it isn&#8217;t right you can go and change it later but at least you have a baseline to work on &#8211; a clean slate is just intimidating and makes the problem worse.</em></li>
<li>There is nowhere comfortable to sit &#8211; <em>Screw comfort &#8211; work until your butt goes numb, then take a break &#8211; or, perhaps find somewhere to sit down &#8211; there were heaps of cars around, even chairs &#8211; I&#8217;m sure you could have borrowed one.</em></li>
<li>If I sit in the car the satellite will lose its alignment &#8211; <em>(This one is quite pathetic) The satellite&#8217;s by your computer, so it in the car, check the signal strength, and adjust the elevation for the difference your weight in the car makes.</em></li>
</ul>
<p>I really wish I could go back and change them. I think that the reason I was procrastinating on this stuff is that I saw it as such as massive task at hand and couldn&#8217;t even get the momentum to break it up into smaller chunks, and see each iteration worked as an achievement, but now things are looking a bit different.</p>
<p>So next time you&#8217;re stuck perhaps try to keep this in mind. Any momentum is good momentum, and try not to get stuck looking at the big picture. If you are a software developer there is always going to be things you are going to have to look at, review and change, later in the future &#8211; so stop being such a perfectionist and just do the damn work.</p>
]]></content:encoded>
			<wfw:commentRss>http://railsmonkey.net/2011/05/on-procrastination/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Quick Note: Crontabs on OpenWRT Devices (mainly: RobinMesh)</title>
		<link>http://railsmonkey.net/2011/03/quick-note-crontabs-on-openwrt-devices-mainly-robinmesh/</link>
		<comments>http://railsmonkey.net/2011/03/quick-note-crontabs-on-openwrt-devices-mainly-robinmesh/#comments</comments>
		<pubDate>Mon, 14 Mar 2011 04:15:50 +0000</pubDate>
		<dc:creator>Matthew Savage</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[cron]]></category>
		<category><![CDATA[openwrt]]></category>
		<category><![CDATA[robinmesh]]></category>
		<category><![CDATA[tips]]></category>
		<category><![CDATA[wireless]]></category>

		<guid isPermaLink="false">http://railsmonkey.net/?p=373</guid>
		<description><![CDATA[I have a few Ubiquiti Wireless Mesh AP devices which I look after for my local cafe&#8217;s (they keep me [...]]]></description>
			<content:encoded><![CDATA[<p><a title="seiko stopwatch by toshikaz, on Flickr" href="http://www.flickr.com/photos/toshikaz/3479498395/"><img src="http://farm4.static.flickr.com/3625/3479498395_ed3422561a_m.jpg" alt="seiko stopwatch" width="240" height="180" align="right" /></a></p>
<p>I have a few Ubiquiti Wireless Mesh AP devices which I look after for my local cafe&#8217;s (they keep me supplied with coffee, I keep them online&#8230; its a great deal). Recently I wanted to add a cron entry to one of these units to purge users from the captive portal at a certain time each day (we were finding that sessions weren&#8217;t being reset properly, and returning users had no luck getting online).</p>
<p>In a normal system this would simply entail adding an entry to the crontab at <strong>/etc/crontabs/root</strong> (yes, the cron processes run as root &#8211; unfortunately this is part of the firmware), however using the RobinMesh firmware I noticed that the crontabs were being reloaded from scratch each time a reboot ran.</p>
<p>Initially I thought the cron entries were coming out of UCI, however after a bit of digging I noticed that there are a few calls to<strong> &#8216;/lib/robin/setcron.sh&#8217;</strong> from the init script at<strong> /etc/rc.d</strong>.</p>
<p>Looking into this script it seems that the cron entries are being loaded each time from this script, so adding my entry was as easy as adding in a new line to the exec block at the end, which is then piped into the crontab executable.</p>
<p>Simple. Hopefully this will save someone else from a headache. And myself, if I forget in the future.</p>
]]></content:encoded>
			<wfw:commentRss>http://railsmonkey.net/2011/03/quick-note-crontabs-on-openwrt-devices-mainly-robinmesh/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Blocked numbers for business&#8230;.. really?</title>
		<link>http://railsmonkey.net/2010/12/blocke-numbers-for-business-really/</link>
		<comments>http://railsmonkey.net/2010/12/blocke-numbers-for-business-really/#comments</comments>
		<pubDate>Fri, 03 Dec 2010 03:47:32 +0000</pubDate>
		<dc:creator>Matthew Savage</dc:creator>
				<category><![CDATA[Business]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[Gripes]]></category>
		<category><![CDATA[opinion]]></category>
		<category><![CDATA[subjective]]></category>

		<guid isPermaLink="false">http://railsmonkey.net/?p=354</guid>
		<description><![CDATA[How many times have you received a call from a blocked number and not wanted to answer it because you have no idea who it is or how much of your time they're going to take up? Businesses should probably think about this a bit more and push to change it - personally I feel this would increase the number of call backs, or even answered calls...]]></description>
			<content:encoded><![CDATA[<p>This is subjective, but I feel that blocked or restricted numbers should not be an option for businesses. Why should businesses have the right to hide behind a hidden number when contacting their customers or other businesses?</p>
<p>I can understand that in situations you don&#8217;t want customers having the DID number of the person they were talking to regarding an inquiry etc, but this is 2010, we can send out text messages with special names instead of numbers, Steve Jobs can make his name come up on your iPhone when he calls you&#8230; why can&#8217;t the teleco send the &#8216;calling from&#8217; number as the main switch or IVR menu number?</p>
<p>It sure would make things a lot easier when someone leaves you voice mail, or you have a missed call &#8211; instead of scrabbling for a pen and paper or trying to remember that 1300 number, which options to press, the reference number, you can just hit &#8216;call back&#8217; and you return to where you are supposed to be.</p>
<p>As I mentioned above, this is subjective, completely my opinion, but when companies wonder why so many people don&#8217;t answer their calls (banks or credit agencies, for instance), and they have a blocked number, you begin to think that common sense is lost once again.</p>
<p>The invention of Caller ID may have been controversial, questionable, but welcomed none the less, but at least don&#8217;t let businesses abuse the privilege of restricting their number &#8211; there really is no need for it.</p>
]]></content:encoded>
			<wfw:commentRss>http://railsmonkey.net/2010/12/blocke-numbers-for-business-really/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Params Filtering in Rails the custom way &#8211; masking the content</title>
		<link>http://railsmonkey.net/2010/11/params-filtering-in-rails-the-custom-way/</link>
		<comments>http://railsmonkey.net/2010/11/params-filtering-in-rails-the-custom-way/#comments</comments>
		<pubDate>Tue, 23 Nov 2010 11:13:16 +0000</pubDate>
		<dc:creator>Matthew Savage</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[filtering]]></category>
		<category><![CDATA[logs]]></category>
		<category><![CDATA[params]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[security]]></category>

		<guid isPermaLink="false">http://railsmonkey.net/?p=347</guid>
		<description><![CDATA[Want to filter out parameters in your rails logs, but don't want to just replace it with [FILTERED]? Its not as hard as you think...]]></description>
			<content:encoded><![CDATA[<p>For an app I have been working on credit card numbers are being submitted. Naturally a credit card number should be filtered out of the application logs &#8211; after all, you don&#8217;t want someone jumping onto you server and copying your logs to get hold of all those juicy credit card numbers? Nor do you want or need to go to the trouble of PCI-DSS Compliance.</p>
<p>I could have easily just setup my param filters as follows:</p>
<pre class="brush:ruby">
  # config/application.rb
  config.filter_parameters += [:password, :card_number, :cvn]
</pre>
<p>However, I want to have the masked card number available in part to be able to trace back any issues via the logs. So, to avoid the issues with the full card being presented I went about figuring out how to change a card number like 4444333322221111 into 4444&bull;&bull;&bull;&bull;&bull;&bull;&bull;&bull;1111.</p>
<p>It turns out that while a fair bit has changed with how you define which params should be filtered, the functionality is still available to pass in a proc to handle the param filtering. So, here&#8217;s how to do it:</p>
<p><em><strong>Important</strong>: If you are going to use the &bull; character in your filter you will need to add <code># encoding: utf-8</code> to the top of you application.rb file</em></p>
<pre class="brush:ruby">
  # config/application.rb
  card_number_filter = Proc.new do |key, value|
    if key.to_s =~ /card_number/i and value.present?
      value.replace("#{value[0,4]}#{"&bull;" * (value.length - 8)}#{value[-4,4]}")
    end
  end
  config.filter_parameters += [:password, :cvn, card_number_filter]
</pre>
<p>See, it&#8217;s simple. One quick thing to note though &#8211; you need to replace the value object its self, not re-assign to it &#8211; you cant use assignment, such as <code>value = "new_value"</code>, you need to use something which modifies the object in place, such as <code>sub!, gsub!, downcase! or replace</code></p>
<p>So, a handy little nugget there &#8211; you can apply this to whatever you want to do with string manipulation &#8211; or more <img src='http://railsmonkey.net/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> .</p>
]]></content:encoded>
			<wfw:commentRss>http://railsmonkey.net/2010/11/params-filtering-in-rails-the-custom-way/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The Giant Automagical ImageMagick and Fonts install script</title>
		<link>http://railsmonkey.net/2010/07/the-giant-automagical-imagemagick-and-fonts-install-script/</link>
		<comments>http://railsmonkey.net/2010/07/the-giant-automagical-imagemagick-and-fonts-install-script/#comments</comments>
		<pubDate>Sat, 31 Jul 2010 10:52:15 +0000</pubDate>
		<dc:creator>Matthew Savage</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[administration]]></category>
		<category><![CDATA[ImageMagick]]></category>
		<category><![CDATA[Linux]]></category>

		<guid isPermaLink="false">http://railsmonkey.net/?p=336</guid>
		<description><![CDATA[A script to install ImageMagick, and its dependencies, without the fuss.]]></description>
			<content:encoded><![CDATA[<p>Recently I&#8217;ve run into issues with inconsistent ImageMagick installations, which mainly manifest in the form of fonts for annotations etc not working properly, or missing delegates.</p>
<p>Finally I got fed up with repeating this drama every time, so in addition to updating my stack scripts I have put together a script which does all the ImageMagick stuff in one hit, for those one-off installs.</p>
<p>This script installs:</p>
<ul>
<li>Ghostscript Fonts 8.11</li>
<li>Freetype 2.4.1</li>
<li>Fontconfig 2.8.0</li>
<li>Ghostscript 8.71</li>
<li>JPEG Lib 8b</li>
<li>Zlib 1.2.5</li>
<li>libTiff 3.8.2</li>
<li>libpng 1.4.3</li>
<li>and finally, ImageMagick 6.6.3-1</li>
</ul>
<p>Download it <a href="http://shares.amasses.net/image_magick_installer">here</a>.</p>
<p>To run (with extra automagical):</p>
<pre class="brush:bash">
wget -O- http://shares.amasses.net/image_magick_installer | sudo sh
</pre>
<p>To run (normally&#8230;):</p>
<pre class="brush:bash">chmod +x image_magick_installer
sudo ./image_magick_installer</pre>
<p>And then to test the install:</p>
<pre class="brush:bash">convert -v</pre>
<p>I have found that occasionally there are errors like:</p>
<blockquote><p>error while loading shared libraries: libMagickCore.so.4: cannot open shared object file: No such file or directory</p></blockquote>
<p>Try running the following, and if it works, put it into a .sh file in /etc/profile.d (e.g. /etc/profile.d/image_magick_ldd.sh):</p>
<pre class="brush:bash">#!/bin/sh

export LDFLAGS="-L/usr/local/lib -Wl,-rpath,/usr/local/lib"
export LD_LIBRARY_PATH="/usr/local/lib"
ldd /usr/local/bin/convert &gt; /dev/null</pre>
<p>Enjoy</p>
]]></content:encoded>
			<wfw:commentRss>http://railsmonkey.net/2010/07/the-giant-automagical-imagemagick-and-fonts-install-script/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Is your build environment &#8216;sane&#8217;&#8230;?</title>
		<link>http://railsmonkey.net/2010/05/is-your-build-environment-sane/</link>
		<comments>http://railsmonkey.net/2010/05/is-your-build-environment-sane/#comments</comments>
		<pubDate>Sun, 16 May 2010 08:57:07 +0000</pubDate>
		<dc:creator>Matthew Savage</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[IT Consulting]]></category>
		<category><![CDATA[ree]]></category>
		<category><![CDATA[testing]]></category>
		<category><![CDATA[ubuntu]]></category>
		<category><![CDATA[vmware]]></category>

		<guid isPermaLink="false">http://railsmonkey.net/?p=293</guid>
		<description><![CDATA[I&#8217;ve been testing a Varnish reverse-proxy/cache setup this weekend to try to resolve the &#8217;80%&#8217; of the problems I&#8217;ve been [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been testing a Varnish reverse-proxy/cache setup this weekend to try to resolve the &#8217;80%&#8217; of the problems I&#8217;ve been dealing with across our websites.</p>
<p>Because I seem to have an aversion to spending extra moneys to run up test servers (ok look, we&#8217;re a small business, and while EC2 is affordable I seem to have a problem where I forget to shut down our instances when I&#8217;m done with them &#8211; this can become expensive), so I&#8217;ve been running Ubuntu 9.10 and 10.04 in both Parallels and VMWare Fusion to test this varnish setup, and at the same time (I&#8217;ve been sidetracked halfway through) upgrading our production environments to Ubuntu 10.04.</p>
<p>In Parallels things were more or less fine, though I was running into some unexpected issues with running the CPU high (100%) while doing some cache-less bench testing. For whatever reason though I decided to swap over to using VMWare with 10.04 (who says we need consistency?).</p>
<p>The install of Ubuntu 10.04 is pretty much straight forward, but where I did run into problems was running my auto-build scripts which sets up our stack (REE, Passenger, nginx et al). Regardless of what I tried REE would always die during its install process, right on the &#8216;<em>checking whether build environment is sane</em>&#8216; test &#8211; in fact the exact error is:</p>
<pre class="brush:bash">checking whether build environment is sane… configure: error: newly created file is older than distributed files!
Check your system clock</pre>
<p>Yes, this is a really really helpful error message. Especially when you check the time and verify that its correct, and synced up with NTP.</p>
<p>So lets look into this a little bit. The &#8216;sane&#8217; check is doing a few things. It writes out the latest timestamp to a file, then it runs <code>ls</code> and checks the timestamp of the file &#8211; if the times are different or something breaks then the environment is not considered &#8216;sane&#8217;, this could be an issue with your coretools or your system clock or what ever&#8230; pick an option, then pull out your hair.</p>
<p>But, in my case &#8211; running on VMWare &#8211; my coretools were completely fine, but the system clock was a little&#8230; funky&#8230; even after kicking off an <code>ntpupdate</code> there was still some issues &#8211;  a very very tiny miniscule offset, but enough to make my environment &#8216;insane&#8217;.</p>
<p>You can confirm this yourself actually, by running the following:</p>
<pre class="brush:shell">for i in `seq 1 60`
do
date
done</pre>
<p>Take not of what the first time printed out is&#8230; then, 1 hour later, check the final time &#8211; it should be exactly the same, but one hour later. In my case I had 20:39:22, and at the end it was 21:39:23 &#8211; yes, its a whole 1 second, but in this case it made a difference.</p>
<p>So, whats the whole point to this? Well, I do have a fix, its actually really simple. Install the VMWare tools. No really, its that simple.</p>
<ol>
<li>From the VMware tools <strong>Virtual Machine</strong> menu, choose <strong>Install VMware Tools</strong></li>
<li>Run the following commands:</li>
</ol>
<pre class="brush:shell">sudo -s
mount /dev/dvd /cdrom
cd /cdrom
tar zxvf VMwareTools-8.2.3-204229.tar.gz -C /tmp
cd /tmp/vmware-tools-distrib
./vmware-install.pl # (and follow the prompts)
</pre>
<p>Hopefully this will help anyone else also bashing their head against this brick wall, if not, m&#8217;eh, I don&#8217;t mind the writing <img src='http://railsmonkey.net/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://railsmonkey.net/2010/05/is-your-build-environment-sane/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>&#8216;Did you mean&#8230;.&#8217; style searching in your database</title>
		<link>http://railsmonkey.net/2010/05/did-you-mean-style-searching-in-your-database/</link>
		<comments>http://railsmonkey.net/2010/05/did-you-mean-style-searching-in-your-database/#comments</comments>
		<pubDate>Tue, 11 May 2010 09:40:09 +0000</pubDate>
		<dc:creator>Matthew Savage</dc:creator>
				<category><![CDATA[Business]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[User Experience]]></category>

		<guid isPermaLink="false">http://blog.amasses.net/?p=281</guid>
		<description><![CDATA[I bet this has happened to everyone, you are in a rush, you mis-type something and instead of writing &#8216;polka-dotted [...]]]></description>
			<content:encoded><![CDATA[<p>I bet this has happened to everyone, you are in a rush, you mis-type something and instead of writing &#8216;<em>polka-dotted socks</em>&#8216; you&#8217;ve come up with &#8216;<em>polka-dotted <strong>sokcs</strong></em>&#8216; &#8211; legitimate mistake, right?</p>
<p>Thankfully Google doesn&#8217;t rub it in our faces by showing 0 results or just plain laughing, and they offer the humble pie with a link saying &#8216;did you mean <em>polka-dotted </em><strong><em>socks</em></strong>?&#8217;&#8230; so how do they do this?</p>
<p>There&#8217;s a few different options (phonetic algorithms) when it comes to working with text and normalizing down to a searchable index. The most common one is <a title="Soundex on Wikipedia" href="http://en.wikipedia.org/wiki/Soundex" target="_blank">Soundex</a>, which reduces a word like <strong><em>Coffee</em></strong> to <strong>C100</strong>, or <strong><em>Chimmichunga</em></strong> to <strong>C525</strong> &#8211; these values can then be used as an index to search on &#8211; more or less using it as an equality comparison (e.g. <strong><em>Chimmychungah</em></strong> also reduces to <strong>C525</strong>, there for they sound alike).</p>
<p>If you&#8217;re working in your database there are a few options you can choose from &#8211; for MySQL you can use <code>SOUNDEX("Coffee")</code> to calculate the value on the server, or you can use a <code>SOUNDS LIKE</code> operator in your where clause. PostgreSQL offers similar options, with <code>SOUNDEX("Chimmichunga")</code> and also <code>DIFFERENCE("Coffee", "Cafe")</code> to find terms within a specific range. However (and this is merely speculation, I haven&#8217;t benchmarked to confirm this) there could be performance issues for large datasets compared to using a precomputed index column &#8212; the reasoning for this is that the database is doing a table-scan, hitting each row, computing the Soundex value and then comparing &#8212; not an efficient way to lookup records in a large dataset.</p>
<p>Of course, this is useful if you are using MySQL or Postgres, but what if you want something a bit more generic, or you have a large dataset? Well, why not setup precomputed indexes?</p>
<p>Take an example web application, you have a form to lookup a location but you don&#8217;t quite know how to spell it&#8230; is it <em>Wollongong</em> or <em>Woolongong</em>? If we assume an existing application the first step is to add a new column for the Soundex value to live in, and index it. For example, with a Rails application using Active Record I would do the following:</p>
<pre class="brush:ruby">require 'text' # Provides access to the algorithms so we don't have to do the hard work (and possibly stuff it up!)

class AddSoundexIndexColumnToLocations < ActiveRecord::Migration
   def self.up
        add_column :locations, :soundex, :string
        add_index :locations, :soundex
         Locations.reset_column_information
         Locations.each do |location|
             location.update_attributes(:soundex => Text::Soundex.soundex(location.name))
        end
    end

    def self.down
        remove_index :locations, :soundex
        remove_column :locations, :soundex
    end
end</pre>
<p>Once this is completed we now have a Locations table populated with the <em>Name</em>, other existing attributes, and now, the <em>Soundex</em> column. Then, searching is quite simple:</p>
<pre class="brush:ruby">require 'text'

# Assuming that this is a postback and you have a form field or query param of name
@locations = Location.find(:all,
                                            :conditions =&gt; ["name = ? or soundex = ?", params[:name], Text::Soundex.soundex(params[:name])])</pre>
<p>This is a very basic example, but it can be used with a number of ORMs or data storage options, i.e. you can use MongoMapper with an indexed key to lookup the values, or even load a YAML file into memory and scan through that (or XML, or JSON or&#8230; you get the idea). In actuality it should actually be 100% agnostic, at the end of the day it&#8217;s just checking equality.</p>
<p>Of course, the solution isn&#8217;t perfect, but its a beginning.</p>
<p>We have used something like this (albeit using the MySQL <code>SOUNDS LIKE</code> match instead of pre-filled indexes &#8211; currently we only have ~50 records to lookup) for our location searches and to help with hacked-urls (i.e. mis-spelt locations in the URL, such as <code>/reports/balina</code> instead of <code>/reports/ballina</code>).</p>
<p>In the case where we return a Soundex result instead of an exact match we also provide the visitor with some text explaining what has happened (e.g. &#8216;We couldn&#8217;t find <em>Woolongong</em>, but did you mean <em>Wollongong</em>?&#8217;) &#8211; but I&#8217;ll leave that up to you and what your user experience requires.</p>
<p>Enjoy, and feel free to shoot me a question if you have any issues making this stuff play nice, I&#8217;ll see what I can do to help.</p>
]]></content:encoded>
			<wfw:commentRss>http://railsmonkey.net/2010/05/did-you-mean-style-searching-in-your-database/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The &#039;hidden&#039; costs of a Rails website</title>
		<link>http://railsmonkey.net/2010/04/the-hidden-costs-of-a-rails-website/</link>
		<comments>http://railsmonkey.net/2010/04/the-hidden-costs-of-a-rails-website/#comments</comments>
		<pubDate>Thu, 29 Apr 2010 09:38:30 +0000</pubDate>
		<dc:creator>Matthew Savage</dc:creator>
				<category><![CDATA[Business]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[IT Consulting]]></category>
		<category><![CDATA[budget]]></category>
		<category><![CDATA[costs]]></category>
		<category><![CDATA[planning]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[saas]]></category>
		<category><![CDATA[services]]></category>
		<category><![CDATA[websites]]></category>

		<guid isPermaLink="false">https://amasses.wordpress.com/?p=277</guid>
		<description><![CDATA[I need to get something out on the &#8216;internets&#8217; &#8211; running a website isn&#8217;t cheap. Don&#8217;t get me wrong &#8211; [...]]]></description>
			<content:encoded><![CDATA[<p>I need to get something out on the &#8216;internets&#8217; &#8211; running a website isn&#8217;t cheap.</p>
<p>Don&#8217;t get me wrong &#8211; you can get away with running a site on almost zero dollars, and we&#8217;ve all heard about those sites running on someone&#8217;s PC under their desk&#8230; but what I&#8217;m touching on here is a &#8216;real&#8217; website.</p>
<p>I&#8217;m the only developer on a website which is somewhat large. Its no where near the level of the big news sites, or the social sites etc, but we get a fair amount of traffic and the codebase is big enough to keep me busy all the time. And to be honest my life would be much easier if I could just push out the latest version of the site and ignore everything else.</p>
<p>But lets be honest &#8211; large websites are complicated, there is always the change (more often then not) that there might be some bugs laying around, and on top of this performance can be an issue. And don&#8217;t even get me started on email and advertising. So what I now hope to accomplish is an inventory of all the &#8216;extras&#8217; which seem to get over looked, but are quite important, for a production website.</p>
<p><span id="more-278"></span><strong>Exception Handling</strong></p>
<p>No one likes to see error messages, but they&#8217;re unfortunately one of those things we have to live with &#8211; lets be honest, no one is perfect (I&#8217;m certainly not) &#8211; but even though we cant guarantee that errors won&#8217;t be a problem we should be ready to handle them properly and log them, so when the time comes and you have angry users complaining that your website isn&#8217;t working you can be rest-assured that you have any error details available to you without the hassle of asking the user what the error message was, what they were doing, what color t-shirt they had on&#8230; you get the picture.</p>
<p>There are a couple of options here, but the one I use for <em>everything</em> is <a title="Hoptoad from Thoughtbot" href="http://www.hoptoadapp.com" target="_blank">HopToad</a> from <a title="Thoughtbot" href="http://www.thoughtbot.com" target="_blank">Thoughtbot</a> &#8211; this is an extremely simple tool to use. Once your signed up online they give you some quick instructions which includes installing a plugin into your Rails application, then running a generator with an api key for your project, and then thats it &#8211; once you go live and if an error occurs Hoptoad sends you a nice email and makes all the details, including a backtrace, the URL the error happened at, the referring page, the environment variables etc, online and within reach.</p>
<p>There are, of course, free alternatives around, and if you really wanted you could just have your app email you when an error occurs, but I&#8217;m sure most people can relate to the situation where your inbox becomes flooded because you forgot to check for a nil? Yeah, Hoptoad prevents this exact problem.</p>
<p>And the cost? <strong>$15/month, for 16 projects</strong> &#8211; very affordable for what it provides, and there&#8217;s some extra bonuses you&#8217;ll stumble upon which make you think &#8216;wow this is worth it&#8217;.</p>
<p><strong>Application Performance</strong></p>
<p>So, errors we&#8217;ve covered. Next question &#8211; do you know how well your website is running? How do you know which areas are the slowest to run, and do you know what the user experience is like?</p>
<p>On this front as well there are a few options &#8211; you could quite easily run <a title="Request Log Analyzer at GitHub" href="http://github.com/wvanbergen/request-log-analyzer" target="_blank">Request Log Analyzer</a> and pass it your latest production log file, but thats not really a real time view, and if you want to look through historical periods its somewhat difficult, involving splitting out your logs based on time stamps &#8211; not my idea of fun.</p>
<p>RPM to the rescue &#8211; <a title="NewRelic" href="http://www.newrelic.com" target="_blank">NewRelic RPM</a> to be exact. I suppose that this is probably the best known &#8216;Rails&#8217; application around. Mind you, its not cheap, but for what it provides its actually invaluable for popular websites.  And what does it provide? Real time metrics, drill down trouble shooting, pretty graphs and more. Really, I&#8217;d just recommend that you give their free version a go &#8211; I&#8217;d wager that you will want to upgrade to get the extra features once you get a taste.</p>
<p>And on top of providing a great product they also sponsored the <a title="Scaling Rails screen cast series" href="http://railslab.newrelic.com/scaling-rails" target="_blank">Scaling Rails</a> screen cast series with <a title="Gregg Pollack at Envy Labs" href="http://envylabs.com/team" target="_blank">Gregg Pollack</a> &#8211; I&#8217;d highly recommend everyone checks out this series.</p>
<p>So how much will this set you back? It varies based on pricing level, but currently we pay about <strong>$200/month &#8211; and its worth every cent.</strong></p>
<p><strong>Server Monitoring</strong></p>
<p>Now we have errors covered off and application performance is taken care of what about your hosting infrastructure? If your using a Rails hosting specialist like Engine Yard or Rails Machine or similar then they&#8217;ve got this covered, skip on to the next point, but if you&#8217;ve rolled your own, be it with your own hardware, or on cloud infrastructure like EC2, it would be very wize to start collecting some metrics about how your machines are actually running.</p>
<p>Of course, there is a myriad of options here, so let me just focus on what we use, which is <a title="Server Density" href="http://www.serverdensity.com/" target="_blank">Server Density</a> &#8211; these guys make monitoring, alerting and metric collection as simple as making a sandwich (well, as long as it isn&#8217;t some fancy sandwich which requires some weird condiment you can only get by milking deep sea predator fish&#8230;). Sign up for an account, setup a server in their system, and once you&#8217;ve installed the Server Density agent, drop in the config details and wait.</p>
<p>Its extremely easy to setup alerts based on thresholds (such as memory free, CPU load, number of request for nginx or apache, even connections to MySQL or MongoDB), and they support notifications via Email, SMS and iPhone push as well (though to be honest, if you publish something controversial which generates some traffic the alerts can become a bit irritating). And if you want to monitor something they don&#8217;t support, and your a bit of a dab hand at Python, they have a brand spanking new plugin framework for you to use.</p>
<p>This has saved me a few times, especially being able to look back in time, see a spike, check out what was happening on my system at that time, and the simplicity is just awesome. Plus, they&#8217;ve been public adopters of MongoDB for their data collection and feedback to the community with their experiences.</p>
<p>Server Density &#8211; <strong>$10 (per server)</strong>, being able to tell your boss that the servers aren&#8217;t really on fire&#8230; priceless (yeah thats kind of lame, sorry).</p>
<p><strong>Email</strong></p>
<p>I&#8217;ve unfortunately discovered, more often then not, that sending emails from web applications is a bit of a thorn in the side (sure, Rails makes this a lot easier with ActionMailer providing views etc). Its not actually the sending thats the issue &#8211; anyone can put together some content and use a library like tmail, Pony, even ActionMailer to shoot off a message &#8211; the real issue is dealing with delivery problems.</p>
<p>Running on Amazon EC2, while amazingly flexible and cost effective, has a slight issue &#8211; the same things that make EC2 appealing to me also make EC2 appealing to spammers. And as a result there are a lot of RBLs, block lists etc, which don&#8217;t like emails from the EC2 address space. Plus, PTR records, you have no control over them.</p>
<p>So why risk the emails not being sent? And what about bounces &#8211; soft and hard, plus do you know what happened with the email after it was received?</p>
<p>I was initially introduced to <a title="SendGrid" href="http://www.sendgrid.net" target="_blank">SendGrid</a> through <a title="Heroku" href="http://www.heroku.com" target="_blank">Heroku</a> (that is another topic all together) &#8211; before that I was hacking about with smtp-tls and Google Apps SMTP to get my emails out. For the site that I work on now there were two options &#8211; use the SMTP server provided by the hosting company (before we moved to EC2), setup our own MTA, or use an external service. The decision time there was less then a second &#8211; straight away I was on the SendGrid page and registering for the company.</p>
<p>SendGrid makes things simple &#8211; I tell my app which SMTP settings to use, which authenticate, of course, and then I get everything I need from SendGrid straight away &#8211; I can turn on open and click tracking, so I know if users are &#8216;doing things&#8217; with the emails we send out, we have domains keys enabled automatically, plus we also get to see if there are any bounces of emails, and compare that to our outgoing amount (more shiny graphs).</p>
<p>And the total cost for this is <strong>$9 per month </strong>- perfect.</p>
<p><strong>To summarize</strong> this hasn&#8217;t covered everything we pay for externally &#8211; there are tools like <a title="Basecamp - you really should use this" href="http://www.basecamphq.com" target="_blank">Basecamp</a> (for the higher level project management and collaboration), <a title="Unfuddle, for your source code hosting and ticket management" href="http://www.unfuddle.com" target="_blank">Unfuddle</a> (for the development project management), <a title="ZenDesk - SaaS Helpdesk software" href="http://www.zendesk.com" target="_blank">Zendesk</a> (for helpdesk.. those pesky users) and <a title="MailChimp - for email campaigns (aka EDM)" href="http://eepurl.com/uM7_" target="_blank">MailChimp</a> (for email campaigns) we use, but its a case of &#8216;different strokes for different folks&#8217; &#8211; but what I&#8217;ve mentioned above are just the basics.</p>
<p>The real take away message here is that there are always other things you need to factor in when your considering when you figure out how much running a website is actually going to cost you. And if your wondering why you don&#8217;t just build this stuff your self.. well, sure, I&#8217;m not stopping you, I just feel that most times its smarter to pay for something already available rather then spending time reinventing the wheel, only to realize what you finished up with is missing a whole lot of stuff.</p>
]]></content:encoded>
			<wfw:commentRss>http://railsmonkey.net/2010/04/the-hidden-costs-of-a-rails-website/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

