<?xml version='1.0' encoding='UTF-8'?><rss xmlns:atom='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' version='2.0'><channel><atom:id>tag:blogger.com,1999:blog-9067288001838449347</atom:id><lastBuildDate>Sun, 08 Apr 2012 17:41:08 +0000</lastBuildDate><category>Coding</category><category>rubber</category><category>Cool Hacks</category><category>Ruby</category><category>Subversion</category><category>Rails</category><category>Sys Admin</category><category>Eclipse</category><category>Neat Stuff</category><category>Mac OS X</category><category>Misc</category><category>Uncategorized</category><category>EC2</category><title>Swapfile for my brain</title><description></description><link>http://simplygenius.com/</link><managingEditor>noreply@blogger.com (Matt Conway)</managingEditor><generator>Blogger</generator><openSearch:totalResults>53</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-9067288001838449347.post-7413773135190845178</guid><pubDate>Thu, 20 Oct 2011 11:52:00 +0000</pubDate><atom:updated>2011-10-20T04:55:44.188-07:00</atom:updated><title>Update to Scripting with Ruby on OS X</title><description>After updating to lion, I needed to tweak the script I had written &lt;a href="http://simplygenius.com/2008/05/replacing-applescript-with-ruby.html"&gt;here&lt;/a&gt;, so here is the updated version with some more comments to help people modify and write their own Ruby/OSX scripts&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#!/usr/bin/ruby&lt;br /&gt;# -*- coding: utf-8 -*-&lt;br /&gt;&lt;br /&gt;# Put this in Library/Scripts/Applications/Terminal&lt;br /&gt;#&lt;br /&gt;# To get the script to show up in menubar,&lt;br /&gt;# run "AppleScript Editor" -&gt; Preferences -&gt; "Show script menu in menu bar"&lt;br /&gt;#&lt;br /&gt;# To figure out what properties are available, "AppleScript Editor" -&gt; File -&gt; "Open Dictionary"&lt;br /&gt;&lt;br /&gt;require 'osx/cocoa'&lt;br /&gt;include OSX&lt;br /&gt;OSX.require_framework 'ScriptingBridge'&lt;br /&gt;&lt;br /&gt;def alert(title, message='', is_error=false)&lt;br /&gt;  puts "Displaying #{is_error ? 'error ' : ''}dialog - #{title}: #{message}"&lt;br /&gt;  if is_error&lt;br /&gt;    NSRunCriticalAlertPanel(title, message, 'OK', nil, nil)&lt;br /&gt;  else&lt;br /&gt;    NSRunAlertPanel(title, message, 'OK', nil, nil)&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;rowSize = 24&lt;br /&gt;colSize = 80&lt;br /&gt;yMin = 22&lt;br /&gt;xMin = 187&lt;br /&gt;xCount = 2&lt;br /&gt;&lt;br /&gt;# To get bundle ID, View Package Contents on App -&gt; Contents/Info.plist -&gt; Bundle ID&lt;br /&gt;term = SBApplication.applicationWithBundleIdentifier_("com.apple.Terminal")&lt;br /&gt;&lt;br /&gt;# set the # of rows and columns (global setting, so set to one tab, sets for all)&lt;br /&gt;# term.windows.first.tabs.first.currentSettings.numberOfRows = rowSize&lt;br /&gt;# term.windows.first.tabs.first.currentSettings.numberOfColumns = colSize&lt;br /&gt;term.defaultSettings.numberOfRows = rowSize&lt;br /&gt;term.defaultSettings.numberOfColumns = colSize&lt;br /&gt;&lt;br /&gt;# sort on title to order according to ⌘N window selection shortcuts, index is some other order&lt;br /&gt;sorted_windows = term.windows.sort_by {|w| w.name.to_s.match(/([0-9]+)$/)[1] }&lt;br /&gt;sorted_windows.each_with_index do |window, i|&lt;br /&gt;  # puts "#{window.index}: #{window.name}"&lt;br /&gt;&lt;br /&gt;  # sizes should be the same for all windows after setting numberOfRows/Cols&lt;br /&gt;  xSize = window.bounds.width&lt;br /&gt;  ySize = window.bounds.height&lt;br /&gt;&lt;br /&gt;  newx = xMin + xSize * (i % xCount)&lt;br /&gt;  newy = yMin + ySize * (i / xCount).to_i&lt;br /&gt;&lt;br /&gt;  rect = NSRect.new(newx, newy, xSize, ySize)&lt;br /&gt;  window.bounds = rect&lt;br /&gt;&lt;br /&gt;  # If setting rect doesn't work, set position instead even though it is&lt;br /&gt;  # deprecated&lt;br /&gt;  # pos = NSPoint.new(newx, newy)&lt;br /&gt;  # window.position = pos&lt;br /&gt;  #&lt;br /&gt;  # size also deprecated&lt;br /&gt;  # size = NSPoint.new(xSize, ySize)&lt;br /&gt;  # window.size = size&lt;br /&gt;end&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/9067288001838449347-7413773135190845178?l=simplygenius.com' alt='' /&gt;&lt;/div&gt;</description><link>http://simplygenius.com/2011/10/update-to-scripting-with-ruby-on-os-x.html</link><author>noreply@blogger.com (Matt Conway)</author><thr:total>0</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-9067288001838449347.post-5760190581479488944</guid><pubDate>Wed, 25 Aug 2010 01:33:00 +0000</pubDate><atom:updated>2010-08-24T19:16:19.047-07:00</atom:updated><title>JConsole via a SOCKS ssh tunnel</title><description>I've been learning how to use cassandra lately, and one of the most useful tools when working with it is to be able to query status via all the JMX hooks it exposes.  At first I was using &lt;a href="http://www.cyclopsgroup.org/projects/jmxterm/"&gt;jmxterm&lt;/a&gt; to query all the available settings, and while this works great, it was tough as a cassandra newb to figure out which beans I needed to query.&lt;br /&gt;&lt;br /&gt;What I wanted to do was use JConsole so that I could browse the available beans without having to know a priori what they were.  Unfortunately, our production system is all remote (ec2), so this makes it tricky to use JConsole.&lt;br /&gt;&lt;br /&gt;At first I tried to use a basic ssh port mapping, but  this didn't work due to RMI's need to create its own ports in the JConsole runtime to which the monitored process tries to connect back to - only the single port is tunnelled by ssh.  There are a number of documented solutions to doing this, but they all seemed very intrusive and hard to setup correctly (e.g. running a hacked jmx agent within your monitored process).&lt;br /&gt;&lt;br /&gt;I then tried using JConsole running remotely but displaying on my local X server, but the performance wasn't that great, and its a pain to have to install all the X runtime on my production system just for running JConsole. &lt;br /&gt;&lt;br /&gt;Eventually I smacked my forehead after remembering that ssh can also act as a SOCKs proxy, which works great for any application that supports it.  Fortunately, JConsole does (in jdk 1.6 at least).&lt;br /&gt;&lt;br /&gt;Here is the bash alias I use to setup the socks connection and connect to my cassandra instance via jconsole.  I have multiple remote remote cassandra hosts, so this lets me run JConsole independently for each.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;function jc {&lt;br /&gt;        host=$1&lt;br /&gt;        proxy_port=${2:-8123}&lt;br /&gt;        jconsole_host=wrongway&lt;br /&gt;        ssh -f -D$proxy_port $host 'while true; do sleep 1; done'        ssh_pid=`ps ax | grep "[s]sh -f -D$proxy_port" | awk '{print $1}'`&lt;br /&gt;        jconsole -J-DsocksProxyHost=localhost -J-DsocksProxyPort=$proxy_port ser&lt;br /&gt;vice:jmx:rmi:///jndi/rmi://${jconsole_host}:8181/jmxrmi&lt;br /&gt;        kill $ssh_pid&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Once this was in my shell environment, I simply run "jc remote_host", and I get a jconsole connected to my cassandra instance on that host.&lt;br /&gt;&lt;br /&gt;Note that you need to set "jconsole_host" in the alias for this to work for you.  I'm not sure why, but Its sensitive to the value in here, and only worked for me for the first entry I had in /etc/hosts (not localhost) that maps my local hostname to 127.0.0.1&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9067288001838449347-5760190581479488944?l=simplygenius.com' alt='' /&gt;&lt;/div&gt;</description><link>http://simplygenius.com/2010/08/jconsole-via-socks-ssh-tunnel.html</link><author>noreply@blogger.com (Matt Conway)</author><thr:total>13</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-9067288001838449347.post-2732302006217075301</guid><pubDate>Wed, 10 Feb 2010 19:39:00 +0000</pubDate><atom:updated>2011-05-27T11:23:26.247-07:00</atom:updated><title>Automating gists with QuickSilver</title><description>&lt;blockquote&gt;&lt;/blockquote&gt;I like to use gist for sharing code snippets.  I like to use QuickSilver for automating common tasks.  To combine the two is fairly simple:&lt;div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;Install the gist gem&lt;/li&gt;&lt;code&gt;&lt;blockquote&gt;gem install gist&lt;/blockquote&gt;&lt;br /&gt;&lt;li&gt;Enable the Terminal Module in QuickSilver Plug-ins&lt;/li&gt;&lt;li&gt;Create a new HotKey Trigger&lt;/li&gt;&lt;li&gt;Hit "." then type the following command into the Select Item field.  You only need the bash part if you installed the gist gem using rvm/ruby instead of the system ruby&lt;blockquote&gt;bash -l -c "pbpaste | gist | pbcopy"&lt;/blockquote&gt;&lt;/li&gt;&lt;li&gt;Tab over to Action field, and select "Run Command in Shell"&lt;/li&gt;&lt;li&gt;Save the trigger, then set whatever hotkey you want - I use Cmd-Shift-G - you might need to restart quicksilver for this to take effect&lt;/li&gt;&lt;/code&gt;&lt;/ol&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;code&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;Now you can select some text, copy to clipboard, then hit Cmd-Shift-G to create a gist from the clipboard contents, ending up with a url to that gist now in the clipboard.&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9067288001838449347-2732302006217075301?l=simplygenius.com' alt='' /&gt;&lt;/div&gt;</description><link>http://simplygenius.com/2010/02/automating-gists-with-quicksilver.html</link><author>noreply@blogger.com (Matt Conway)</author><thr:total>0</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-9067288001838449347.post-8908167933306548737</guid><pubDate>Wed, 22 Apr 2009 21:38:00 +0000</pubDate><atom:updated>2009-04-22T15:01:07.652-07:00</atom:updated><title>Mysql connect/read/write timeouts in rails</title><description>Ran into a problem in production recently where mysql/OS ran out of memory, didn't die, but didn't actually do anything, so connections to it were still open. As a result, the rails mysql adapter would just hang indefinitely in the middle of a request to mysql, with no exception being thrown, thereby not triggering our db failover and causing our entire site to come to a screeching halt!&lt;br /&gt;&lt;br /&gt;In order to prove my hypothesis correct, not to mention to have a way to test that I'd fixed the problem, I first had to be able to duplicate this problem, i.e. I had to simulate mysql hanging without actually killing it. Fortunately *nix has a good way of doing this via kill:&lt;br /&gt;&lt;br /&gt;To stop a process: kill -s STOP mysqld_pid&lt;br /&gt;To resume it: kill -s CONT mysqld_pid&lt;br /&gt;&lt;br /&gt;This duplicated the problem perfectly - any ActiveRecord::Base.execute would hang indefinitely.&lt;br /&gt;&lt;br /&gt;Digging around some, I discovered that the ruby mysql gem does have a way to set timeouts, but this config is not exposed in database.yml, so I dutifully forked rails (yay github!), patched it, and solved my problem.&lt;br /&gt;&lt;br /&gt;Here's the &lt;a href="https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/2544"&gt;Rails issue&lt;/a&gt; from which you can get the patch&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9067288001838449347-8908167933306548737?l=simplygenius.com' alt='' /&gt;&lt;/div&gt;</description><link>http://simplygenius.com/2009/04/mysql-connectreadwrite-timeouts-in.html</link><author>noreply@blogger.com (Matt Conway)</author><thr:total>2</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-9067288001838449347.post-7619936824361256443</guid><pubDate>Sun, 05 Apr 2009 02:07:00 +0000</pubDate><atom:updated>2009-04-04T19:26:41.151-07:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>Ruby</category><category domain='http://www.blogger.com/atom/ns#'>rubber</category><category domain='http://www.blogger.com/atom/ns#'>Sys Admin</category><category domain='http://www.blogger.com/atom/ns#'>EC2</category><category domain='http://www.blogger.com/atom/ns#'>Rails</category><title>Added EBS support to rubber</title><description>I recently committed a change to &lt;a href="http://wiki.github.com/wr0ngway/rubber"&gt;rubber&lt;/a&gt; that adds some basic support for Amazon EC2's persistent volumes (Elastic Block Store, EBS).  The way it works is that you tell rubber the host volume configurations, and those volumes will get created/formatted/mounted automatically on those hosts.  If the host gets destroyed and recreated, the volume will get remounted without being formatted.&lt;br /&gt;&lt;br /&gt;For example, in rubber.yml you'd have something like:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;hosts:&lt;br /&gt;db01:&lt;br /&gt;  availability_zone: us-east-1a&lt;br /&gt;  ec2_volumes:&lt;br /&gt;    - size: 100 # size of vol in GBs&lt;br /&gt;    zone: us-east-1a # zone to create volume in, needs to match host's zone&lt;br /&gt;    device: /dev/sdh # OS device to attach volume to&lt;br /&gt;    mount: /mnt/mysql_data # The directory to mount this volume to&lt;br /&gt;    filesystem: ext3 # the filesystem to create on volume&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;When you first create/bootstrap the db01 hostname, the volume will automatically get created, formatted and mounted to the given path on the instance.  If you then destroy db01, you're given the option to cleanup the volume, but if you don't, recreating db01 will automatically re-attach and remount the volume (without formating it).&lt;br /&gt;&lt;br /&gt;This addresses the use case (mine) where you assign persistent storage to say a DB server, and want to be able to quickly rebuild that instance if it dies, without having to figure out which ec2 volume IDs map to which instance IDs.  Just make sure you answer NO to destroying the instance if you do a rubber:destroy and want to keep the volume   around for when you recreate the instance.&lt;br /&gt;&lt;br /&gt;I also changed Elastic IPs to work in a similar fashion - you specify you want an instance to have an elastic ip, and rubber allocates and assigns the static ip to that instance, remembering the IP/instance mapping so that if you destroy/recreate the instance, it will get back the same IP.&lt;br /&gt;&lt;br /&gt;Similar to the volumes support, when you destroy an instance you get prompted to cleanup the IP, but if you answer NO it keeps the mapping around to reassign it to the instance at recreation time.&lt;br /&gt;e.g.&lt;br /&gt;&lt;pre&gt;hosts:&lt;br /&gt; web01:&lt;br /&gt;   use_static_ip: true&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/9067288001838449347-7619936824361256443?l=simplygenius.com' alt='' /&gt;&lt;/div&gt;</description><link>http://simplygenius.com/2009/04/added-ebs-support-to-rubber.html</link><author>noreply@blogger.com (Matt Conway)</author><thr:total>0</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-9067288001838449347.post-5303670652772598438</guid><pubDate>Tue, 10 Feb 2009 22:28:00 +0000</pubDate><atom:updated>2009-02-10T16:06:44.194-08:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>Mac OS X</category><category domain='http://www.blogger.com/atom/ns#'>Sys Admin</category><title>Time Capsule restores from a secure shared disk</title><description>My macbook pro died this week.  Turns out my logic board went caput, so they had to put in a new one.  In the interim, I had a spare I could use, but first I had to do a full system restore from my backup on our Time Capsule.&lt;br /&gt;&lt;br /&gt;We have our time capsule setup for secure shared disks with accounts so that each user has their own password protected private share so that no other user can snoop on their backup.&lt;br /&gt;&lt;br /&gt;Unfortunately, the Full System Restore available when booting the Leopard DVD failed to see my backup even though I used my private time capsule account credentials when connecting to it.  All I could see were other backups that were available on the public share, leading me to believe that my credentials were working to mount the image, but the restore app wasn't smart enough to mount my private mount point instead of (or in addition to) the public one.  I tried calling apple support, and after escalating the issue, all they could suggest was to copy my backup from the private share to the public one.  Needless to say, it takes a really long time to a couple of hundred GB even when connected directly to the time capsule using an ethernet cable.&lt;br /&gt;&lt;br /&gt;Fortunately, when booting from the Leopard DVD, one also has access to a Terminal.  By manually mounting the private share from Terminal, the full system restore UI was then able to see my private share and the restore was able to take place.&lt;br /&gt;&lt;br /&gt;To Summarize, Boot from the Leopard DVD, select Utilities-&gt;Terminal, then use the mount command to mount your private time capsule share.  In my case, my username and share are named the same - mconway - I think this is just the way time capsule works, so the pattern should be the same for you.  Also, I had to add the .local to the end of the time capsule's name for the mount to work.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:bash"&gt;&lt;br /&gt;# Create directory to mount to&lt;br /&gt;mkdir -p /Volumes/mconway&lt;br /&gt;# Do the mount&lt;br /&gt;mount -t afp 'afp://mconway:mypassword@my-time-capsule-name.local/mconway' /Volumes/mconway&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Once mounted, you can verify with a "ls /Volumes/mconway" and you should see the sparseimage for your backup.  Quit Terminal, go to Utilities-&gt;Full System Restore, and your backup should be visible, though you might have to lead the UI through the hoops by connecting to your time capsule and typing in your credentials again.&lt;br /&gt;&lt;br /&gt;Hopefully this will save someone else the hours of grief I was faced with.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9067288001838449347-5303670652772598438?l=simplygenius.com' alt='' /&gt;&lt;/div&gt;</description><link>http://simplygenius.com/2009/02/time-capsule-restores-from-secure.html</link><author>noreply@blogger.com (Matt Conway)</author><thr:total>0</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-9067288001838449347.post-1245732247878261347</guid><pubDate>Tue, 30 Dec 2008 22:35:00 +0000</pubDate><atom:updated>2008-12-30T14:51:21.783-08:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>Cool Hacks</category><category domain='http://www.blogger.com/atom/ns#'>Ruby</category><category domain='http://www.blogger.com/atom/ns#'>Coding</category><title>Converting to blogger from wordpress</title><description>The HTPC I was running wordpress on got replaced with an appletv+boxee (&lt;a href="http://boxee.tv/"&gt;boxee&lt;/a&gt; rocks btw), and rather than waste electricity just to run my blog, I figured I'd convert it to a hosted solution.  I don't want to have to do this again any time soon, so I wanted to use a hosted service thats pretty reliable and will be around for a while.   I didn't feel like paying wordpress for the privilege of mapping a custom domain, so blogger it was.  Problem was, I couldn't get my wordpress export imported into blogger.  I tried &lt;a href="http://code.google.com/p/wxr2blogger/"&gt;wxr2blogger&lt;/a&gt;, but while the script ran fine, blogger wouldn't actually import the results.  I also found a &lt;a href="http://snippets.dzone.com/posts/show/6659"&gt;ruby script &lt;/a&gt;which seemed to work, but wouldn't pull my comments across, so I ended up tweaking it so that it would work with comments as well.  Here is my improved &lt;a href="http://gist.github.com/41781"&gt;wordpress2bloggger.rb&lt;/a&gt; script.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9067288001838449347-1245732247878261347?l=simplygenius.com' alt='' /&gt;&lt;/div&gt;</description><link>http://simplygenius.com/2008/12/converting-to-blogger-from-wordpress.html</link><author>noreply@blogger.com (Matt Conway)</author><thr:total>0</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-9067288001838449347.post-9043054772024730467</guid><pubDate>Wed, 09 Jul 2008 21:17:00 +0000</pubDate><atom:updated>2008-12-30T14:08:09.545-08:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>Ruby</category><title>Rubber presentation at Boston Ruby Group</title><description>I gave a presentation about using &lt;a href="http://github.com/wr0ngway/rubber/wikis" title="Deploy Rails on EC2 with Rubber"&gt;rubber&lt;/a&gt; to deploy rails apps to ec2 to the Boston Ruby Group on Tuesday July 8th, 2008.  I'm not quite sure how good my speaking skills are, but it seemed to go well.  See the slides on &lt;a href="http://www.slideshare.net/wr0ngway" title="Rubber presentation"&gt;slideshare&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9067288001838449347-9043054772024730467?l=simplygenius.com' alt='' /&gt;&lt;/div&gt;</description><link>http://simplygenius.com/2008/07/rubber-presentation-at-boston-ruby.html</link><author>noreply@blogger.com (Matt Conway)</author><thr:total>2</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-9067288001838449347.post-2795030492208027392</guid><pubDate>Sat, 31 May 2008 16:17:00 +0000</pubDate><atom:updated>2008-12-30T14:08:09.527-08:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>rubber</category><title>RailsConf 2008</title><description>In Portland, Oregon all this weekend for RailsConf 2008, any like-minded readers interested in chatting over a beer?I gave a lightning talk on &lt;a href="http://rubber.rubyforge.org/svn/trunk/README"&gt;rubber&lt;/a&gt; today, if anyone wangts a more detailed demo, seek me out (twitter: mattconway). &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9067288001838449347-2795030492208027392?l=simplygenius.com' alt='' /&gt;&lt;/div&gt;</description><link>http://simplygenius.com/2008/05/railsconf-2008.html</link><author>noreply@blogger.com (Matt Conway)</author><thr:total>1</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-9067288001838449347.post-4589945369445337489</guid><pubDate>Thu, 29 May 2008 15:24:00 +0000</pubDate><atom:updated>2011-10-20T04:58:01.898-07:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>Ruby</category><title>Replacing AppleScript with Ruby</title><description>I had a brief run-in with AppleScript trying to overcome an &lt;a href="http://simplygenius.com/2006/05/os-x-terminal-bug_30.html"&gt;OS X terminal bug.&lt;/a&gt;  and its not something I enjoyed.  I would much rather be able to do scripts like this in a language I'm more comfortable in like ruby.  I've known for a while that one of the enhancements in OS X Leopard is that it has native support for scripting the UI from within other scripting languages like python and ruby, however, I didn't realize that I could drop those scripts in the user scripts folder (~/Library/Scripts) and have them available from the scripts toolbar icon.&lt;a name='more'&gt;&lt;/a&gt; Well, one can!  The trick to dong this is that the script has to be executable (chmod +x ~/Library/Scripts/Application/Terminal/Layout.rb), and needs to have a shebang to the desired  interpreter (#!/usr/bin/ruby as the first line.) Finally I can get rid of the only AppleScript code I was forced to write.  Here is a (better!) ruby equivalent of the AppleScript from the link above.&lt;br /&gt;&lt;br /&gt;&lt;pre lang="ruby"&gt;&lt;br /&gt;#!/usr/bin/ruby&lt;br /&gt;&lt;br /&gt;require 'osx/cocoa'&lt;br /&gt;include OSX&lt;br /&gt;OSX.require_framework 'ScriptingBridge'&lt;br /&gt;&lt;br /&gt;yMin = 22&lt;br /&gt;xMin = 187&lt;br /&gt;xSize = 504&lt;br /&gt;ySize = 365&lt;br /&gt;xCount = 2&lt;br /&gt;&lt;br /&gt;term = SBApplication.applicationWithBundleIdentifier_("com.apple.Terminal")&lt;br /&gt;sorted_windows = term.windows.sort_by {|w| w.name.to_s.match(/([0-9]+)$/)[1] }&lt;br /&gt;sorted_windows.each_with_index do |window, i|&lt;br /&gt;  newx = xMin + xSize * (i % xCount)&lt;br /&gt;  newy = yMin + ySize * (i / xCount).to_i&lt;br /&gt;  # Setting rect doesn't work, so set position instead even though it is&lt;br /&gt;  # deprecated&lt;br /&gt;  # rect = NSRect.new(newx, newy, xSize, ySize)&lt;br /&gt;  # window.bounds = rect&lt;br /&gt;  pos = NSPoint.new(newx, newy)&lt;br /&gt;  window.position = pos&lt;br /&gt;  # size doesn't work reliably&lt;br /&gt;  # size = NSPoint.new(xSize, ySize)&lt;br /&gt;  # window.size = size&lt;br /&gt;end&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/9067288001838449347-4589945369445337489?l=simplygenius.com' alt='' /&gt;&lt;/div&gt;</description><link>http://simplygenius.com/2008/05/replacing-applescript-with-ruby.html</link><author>noreply@blogger.com (Matt Conway)</author><thr:total>1</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-9067288001838449347.post-339776522838458467</guid><pubDate>Tue, 11 Mar 2008 11:44:00 +0000</pubDate><atom:updated>2008-12-30T14:08:09.500-08:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>Subversion</category><title>Capistrano and ssh connection limit</title><description>We use capistrano to deploy our rails applications from a subversion repository that is accessed using svn+ssh.  Recently we ran into a problem where Capistrano was unable to connect to subversion from some of the deployment hosts with an error like:&lt;p&gt;&lt;code&gt;*** [err :: host.domain.com] ssh_exchange_identification: Connection closed by remote host&lt;/code&gt;&lt;/p&gt;Since capistrano tries to fire off N svn checkouts simultaneously, it was running into a connection limit for ssh on the the subversion server.  Turns out there is a MaxStartups setting for sshd_config which effectively determines how many clients can be trying to connect simultaneously.  It defaults to 10, and our failures started happening when we went above 10.  Changing the value to 50 on our svn/ssh server cleared up the problem.&lt;br class="webkit-block-placeholder" /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9067288001838449347-339776522838458467?l=simplygenius.com' alt='' /&gt;&lt;/div&gt;</description><link>http://simplygenius.com/2008/03/capistrano-and-ssh-connection-limit.html</link><author>noreply@blogger.com (Matt Conway)</author><thr:total>0</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-9067288001838449347.post-1504078687905861081</guid><pubDate>Mon, 28 Jan 2008 16:12:00 +0000</pubDate><atom:updated>2008-12-30T14:08:09.453-08:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>EC2</category><title>Client for nettica dns service</title><description>One of the drawbacks of EC2 is that there are no static IPs to be had, so short of using an external (to ec2) solution, the only way to have redundant load balancers is to use dns round robin.  If a load balancer instance goes down, we should ideally remove it from the round robin so that clients don't continue to use the dead IP.&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;a href="http://www.nettica.com"&gt;Nettica&lt;/a&gt; is one of the few dns providers that has an API that allows changes to round robin records.  They have a reference implementation in Java, but since I'm a ruby fanboy these days, I figured it would be nice to have a ruby version instead, so I added one to rubyforge:  &lt;a href="http://rubyforge.org/projects/nettica/"&gt;nettica ruby client.&lt;/a&gt;  I did it as a gem, so assuming I released it correctly, you should be able to do a "sudo gem install nettica" and then run the simple test script "nettica -u my_user -p my_secret -c list_zones".  This script still needs to be expanded to exercise the full api.&lt;a href="http://rubyforge.org/projects/nettica/"&gt; &lt;/a&gt;&lt;br /&gt;&lt;br /&gt;One thing that blocked me for the longest time was that the nettcia API required the password to be sent in Base64 encoding, which I was doing, but for some reason the ruby Base64.encode64() method was adding a newline to the end of the encoded string.  Once I stripped that out, it all seems to work fine.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9067288001838449347-1504078687905861081?l=simplygenius.com' alt='' /&gt;&lt;/div&gt;</description><link>http://simplygenius.com/2008/01/client-for-nettica-dns-service.html</link><author>noreply@blogger.com (Matt Conway)</author><thr:total>0</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-9067288001838449347.post-630760328687523201</guid><pubDate>Mon, 28 Jan 2008 15:30:00 +0000</pubDate><atom:updated>2008-12-30T14:08:09.443-08:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>EC2</category><title>Deploying Rails Apps to EC2 with Capistrano</title><description>I've created yet another system for deploying rails apps to ec2 using capistrano.  None of the others were doing it for me, primarily because I needed a way to deploy/configure/scale-up to multiple instances as needed.&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;  What makes this system different?&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;	&lt;li&gt;Role and/or host based configuration of instances&lt;/li&gt;&lt;br /&gt;	&lt;li&gt;All configuration for your instances lives in your project's source tree and gets applied on deploy&lt;/li&gt;&lt;br /&gt;	&lt;li&gt;Configuration system handles dynamically adding instances&lt;/li&gt;&lt;br /&gt;	&lt;li&gt;Configuration templates for sharing deployment scenarios&lt;/li&gt;&lt;br /&gt;	&lt;li&gt;Start with a single instance and scale up as needed without editing config&lt;/li&gt;&lt;br /&gt;	&lt;li&gt;Use whatever AMIs you want (so long as they are debian based :)&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;You can find the &lt;a href="http://rubber.rubyforge.org/svn/trunk/README"&gt;README&lt;/a&gt; file in subversion on rubyforge (project &lt;a href="http://rubyforge.org/projects/rubber/"&gt;rubber&lt;/a&gt;).  You can install the framework from subversion as a rails plugin in the usual way - the README walks you through a demo using the plugin on a dummy rails app, and there is no need to check anything into subversion to do the demo.&lt;br /&gt;&lt;br /&gt;This is still very much a work in progress, so don't use it in production, and expect things to drastically change requiring you to reinstall and reconfigure.&lt;br /&gt;&lt;br /&gt;Any feedback appreciated, but check the &lt;a href="http://rubber.rubyforge.org/svn/trunk/TODO"&gt;TODO&lt;/a&gt; first :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9067288001838449347-630760328687523201?l=simplygenius.com' alt='' /&gt;&lt;/div&gt;</description><link>http://simplygenius.com/2008/01/deploying-rails-apps-to-ec2-with.html</link><author>noreply@blogger.com (Matt Conway)</author><thr:total>0</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-9067288001838449347.post-8063651847833758496</guid><pubDate>Sat, 26 Jan 2008 22:27:00 +0000</pubDate><atom:updated>2008-12-30T14:08:09.433-08:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>EC2</category><title>Using Capistrano without source control</title><description>I'm in the process of writing some capistrano recipes to make deploying to Amazon's Elastic Compute Cloud (ec2) easier.  Since I'm making this project available for general consumption, I wanted a way to make it easy for someone to try it out without having to check something into source control.&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Fortunately, the capistrano code is nicely organized, and that made it easy for me to add a "noscm" provider that will work with the "copy" deploy strategy to simply copy the projects directory tree to a remote server rather than trying to check it out from the remote server.  You can get the  code here: &lt;a href="http://rubber.rubyforge.org/svn/trunk/lib/capistrano/noscm.rb"&gt;http://rubber.rubyforge.org/svn/trunk/lib/capistrano/noscm.rb&lt;/a&gt; and then add the following lines to your deploy script to get it to work:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;require 'capistrano/noscm'&lt;br /&gt;set :scm, :noscm&lt;br /&gt;set :deploy_via, :copy&lt;br /&gt;set :copy_strategy, :export&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;This works for my limited use case, YMMV - things like "cap deploy:pending:diff" definately won't work as all I've implemented from the capistrano scm interface is the "export" ability.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9067288001838449347-8063651847833758496?l=simplygenius.com' alt='' /&gt;&lt;/div&gt;</description><link>http://simplygenius.com/2008/01/using-capistrano-without-source-control.html</link><author>noreply@blogger.com (Matt Conway)</author><thr:total>0</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-9067288001838449347.post-4298404486554089837</guid><pubDate>Sat, 26 Jan 2008 21:57:00 +0000</pubDate><atom:updated>2008-12-30T14:08:09.410-08:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>Sys Admin</category><title>Mounting Xen DomU LVM disk in Dom0</title><description>I setup a xen based system for our production environment at &lt;a href="http://www.mobicious.com"&gt;work&lt;/a&gt;.  I'm using LVM throughout for all the benefits it provides (resizing, snapshot backups, etc).  Each domU gets its own logical volume on dom0's volume group.  This logical volume actually looks like an entire physical disk to the domU, and the domU then further partitions it into a boot partition and a nested LVM partition (swap + root fs).  Aren't the layers of unix file abstractions a thing of beauty to behold? :)&lt;br /&gt;&lt;br /&gt;In retrospect I probably should have mapped LVM logical volumes direct from dom0 as partitions in domU rather than having domU add the extra LVM layer on top - though reading around shows that this _may_ not be supported in the future, so...&lt;a name='more'&gt;&lt;/a&gt;Recently I completely horked our mysql db slave replica and needed to re-replicate the master to the db.  Since our DB is ~ 60GB, I didn't want to shut down (read lock) our master DB for the length of time it would take to copy it over to the slave.  The solution to this would be to use an LVM snapshot.  This way I could read lock the master db, create the LVM snapshot (very quick - a few seconds at most), unlock the master, then copy the data from the snapshot to the slave at my leisure, letting standard db replication do the catch up later.&lt;br /&gt;&lt;br /&gt;For those not in the know about DB repication, one has to make a copy of the master and record the position in its transaction log at that point in time - this way the slave can know where in the transaction log to start repicating from once it comes up with the copy of the data up to that point.&lt;br /&gt;&lt;br /&gt;Ok, so, now knowing what I needed to do, I just needed to do it - not as easy as I thought it would be due to the extra layer of LVM.&lt;br /&gt;&lt;br /&gt;Fortunately, googling around found me my solution, which I'm recording here for the next time I need to do it :)&lt;br /&gt;&lt;br /&gt;Basically, the trick is two fold, frst we have to use kpartx to map the partitions from our virtual disk into partition devices in /dev.  Then we have to tell LVM to rescan these devices to find our embedded LVM partition, and activate the logical volumes on there so that we can then mount them as regular filesystems.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;lvcreate --size 1G --snapshot --name ss_dbmaster /dev/vol1/dbmaster&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;kpartx -av /dev/vol1/ss_dbmaster&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;vgscan&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;lvscan    inactive          '/dev/VolGroup00/LogVol00'&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt; [61.84 GB] inherit    inactive          '/dev/VolGroup00/LogVol01' [2.00 GB] inherit&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;lvchange -ay /dev/VolGroup00/LogVol00&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;lvscan    ACTIVE            '/dev/VolGroup00/LogVol00' [61.84 GB] inherit&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;mount -t ext3 /dev/VolGroup00/LogVol00 /tmp/dbmaster/&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Lets hope I don't have to do that again anytime soon!  I just think its cool how unix can have these layers of abstractions between files and partitions, with files in partitions and partitions in files :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9067288001838449347-4298404486554089837?l=simplygenius.com' alt='' /&gt;&lt;/div&gt;</description><link>http://simplygenius.com/2008/01/mounting-xen-domu-lvm-disk-in-dom0.html</link><author>noreply@blogger.com (Matt Conway)</author><thr:total>2</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-9067288001838449347.post-5678922399940943162</guid><pubDate>Fri, 21 Sep 2007 19:35:00 +0000</pubDate><atom:updated>2008-12-30T14:08:09.381-08:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>Misc</category><title>Wireless Shenanigans</title><description>To date, my wireless setup at home consists of 2 linksys WRT54Gs modded with the &lt;a href="http://openwrt.org/"&gt;OpenWRT&lt;/a&gt; firmware + &lt;a href="http://x-wrt.org/"&gt;x-wrt (webif2)&lt;/a&gt; for a better web ui.  One of these routers serves as my gateway/firewall and the other connects my upper floors to the gateway via WDS (basically, its only there so my Series-1 Tivo can get online as the only mod I have for it is a wired ethernet card :)  I also have a server (mythtv) which connects to my gateway via an ethernet cable cleverly hidden under a rug between the living room and study.  Something my wife isn't too happy with! :)&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;Since my macbook pro has wireless N, I wanted to make use of it transferring files to/from my home server.  Since my home server is a mythtv box, the files I transfer are usually large video ones, and it would be nice to have 802.11n networking for the speed.  Also, my photo printer (HP photosmart 8250) sits above my myth box in the living room, and I haven't had much luck getting it to work from OSX -&gt; myth box (CUPS) - it prints ok, but I can't get OS X to select the 4x6 paper feed when printing photos.&lt;br /&gt;&lt;br /&gt;Enter the famed $100 iphone rebate, and I have a recipe for buying the Airport Extreme 802.11N wireless router which has a usb port for printer/storage sharing.  My hope is to use it for a WDS link between my myth box and gateway thereby eliminating the cabling, allow a better experience using my printer, and allow me to have a high speed connection to my myth box from my macbook.&lt;br /&gt;&lt;br /&gt;Setting it up was fairly painless once I chose the manual setup option - I disabled all the stuff that my gateway already provides (DHCP, etc).  I'm happy to report that the printer sharing works really well - basically no different than if the printer is connected via usb!  I'm also able to get good speed between my macbook and myth box.   My only unsolved issue so far has to do with connecting the airport to my linksys using WDS.&lt;br /&gt;&lt;br /&gt;The only way I can get WDS to work between the airport &lt;-&gt; linksys is if I disable encryption on the link.  Normally, I use WPA+AES for my wireless and WDS connections, and that works fine for both my wireless connections from my macbook as well as for WDS between the routers.  However, no matter which encryption settings I tried (all combinations of WPA1/2, AES, TKIP - didn't try WEP), I was unable to get the airport to connect via WDS to the linksys.&lt;br /&gt;&lt;br /&gt;Things left to try:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;	&lt;li&gt;My Openwrt version is about 6 months old, so maybe an upgrade would help.&lt;/li&gt;&lt;br /&gt;	&lt;li&gt;WEP - airport wouldn't accept the key I generated from the linksys size, not sure whats up there, but I'm not keen on using something as insecure as WEP anyway.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Until I get encrypted WDS working between airport/linksys, I'm sticking with the ethernet cable.&lt;br /&gt;If anyone has gotten this to work, I'd appreciate some pointers so that I can keep my wife happy (not those kind of pointers! ;)&lt;br /&gt;&lt;br /&gt;As a side note, I did notice something interesting with the working (but unencrypted) WDS connection between the airport/linksys.  If I configured the airport to have the same SSID as the linksys, my macbook only achieved 802.11g speeds when connected to that SSID.  However, if I gave it its own SSID different from the linksys' own, and connected my macbook using that SSID, I was able to achieve N speeds.  The WDS link was up and functioning in both directions in either case.  Anyone trying to use WDS in a mixed N/G/B setup take note if you care about speed!&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Update:&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;As another side note, my primitive benchmarks (scping a large file from macbook to myth box) yielded the following:&lt;br /&gt;&lt;br /&gt;&lt;table&gt;&lt;br /&gt;&lt;th&gt;Speed (MB/s)&lt;/th&gt;&lt;th&gt;Configuration&lt;/th&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;1.5&lt;/td&gt;&lt;td&gt;Connecting to airport with Shared G SSID, WDS, no encryption&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;3.1&lt;/td&gt;&lt;td&gt;Connecting to airport with Split N/G SSID, WDS, no encryption&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;5.1&lt;/td&gt;&lt;td&gt;Connecting to airport with no WDS, Radio in n/b/g compatibility mode&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;9.1&lt;/td&gt;&lt;td&gt;Connecting to airport with no WDS, Radio in  only (5GHz) mode&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;Looks like my wife is going to have to live with that cable for now :)&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/9067288001838449347-5678922399940943162?l=simplygenius.com' alt='' /&gt;&lt;/div&gt;</description><link>http://simplygenius.com/2007/09/wireless-shenanigans.html</link><author>noreply@blogger.com (Matt Conway)</author><thr:total>4</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-9067288001838449347.post-7894307320463934375</guid><pubDate>Wed, 12 Sep 2007 15:03:00 +0000</pubDate><atom:updated>2008-12-30T14:08:09.336-08:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>Misc</category><title>Create your own ringtone</title><description>We just added a cool feature called Make My Ringtone, where you can turn any MP3 file into a custom ringtone for your phone. It’s free, easy to use, and works on all major U.S. carriers including Verizon.&lt;br /&gt; &lt;br /&gt;To check it out,&lt;br /&gt;1.       Go to &lt;a href="http://www.mobicious.com/ringtones/new"&gt;www.mobicious.com/ringtones/new&lt;/a&gt;&lt;br /&gt;2.       Select an MP3 file from your desktop&lt;br /&gt;3.       Choose and preview any 20 second clip&lt;br /&gt;4.       Send your custom ringtone to your mobile phone&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9067288001838449347-7894307320463934375?l=simplygenius.com' alt='' /&gt;&lt;/div&gt;</description><link>http://simplygenius.com/2007/09/create-your-own-ringtone.html</link><author>noreply@blogger.com (Matt Conway)</author><thr:total>6</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-9067288001838449347.post-4188540828666377575</guid><pubDate>Fri, 29 Jun 2007 12:05:00 +0000</pubDate><atom:updated>2008-12-30T14:08:09.280-08:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>Misc</category><title>Camping for an iPhone</title><description>Yes, I actually am - I think this is the first tme I have ever camped for anything.  Not sure if one can call sitting in line for 3 hours "camping", but is as close as I'll ever come :)&lt;br /&gt;&lt;br /&gt;For those nearby - the AT&amp;T store on Needham St in Needham MA, only has abou 40 people in line.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9067288001838449347-4188540828666377575?l=simplygenius.com' alt='' /&gt;&lt;/div&gt;</description><link>http://simplygenius.com/2007/06/camping-for-iphone.html</link><author>noreply@blogger.com (Matt Conway)</author><thr:total>5</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-9067288001838449347.post-6681170572567972273</guid><pubDate>Fri, 15 Jun 2007 15:13:00 +0000</pubDate><atom:updated>2008-12-30T14:08:09.263-08:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>Rails</category><title>Web crawling with Ruby</title><description>Learned a little bit about &lt;a href="http://scrubyt.org/"&gt;scRUBYt!&lt;/a&gt; today (damn thats hard to type!).&lt;br /&gt;&lt;br /&gt;It looks like a pretty cool way to do web crawlers.  To use it, you define a "learning" crawler using the scRUBYt! DSL, which combined with the actual site at a specific point in time, creates the real crawler to do the dirty work - essentially, example text gets converted to xpath expressions.  The cool thing about this is that when the site changes, one has to do minimal changes to create a new working crawler, not to mention that creating the crawler in the first place is a lot easier.&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The examples on the site are a little out of date, but here is a simple one which shows the basics.  The learning crawler learns how to extract URLs on a google search for 'ruby', but then the production version ends up being able to crawl the urls for any search term.  It also automatically crawls to the next page by looking for the 'Next' link.&lt;br /&gt;&lt;br /&gt;The learning crawler that you write:&lt;br /&gt;&lt;pre lang="ruby" line="1"&gt;&lt;br /&gt;require 'rubygems'&lt;br /&gt;require 'scrubyt'&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;google_data = Scrubyt::Extractor.define do&lt;br /&gt;  fetch 'http://www.google.com/ncr'&lt;br /&gt;  fill_textfield 'q', 'ruby'&lt;br /&gt;  submit&lt;br /&gt;&lt;br /&gt;  link "Ruby Programming Language/@href"&lt;br /&gt;  next_page "Next", :limit =&gt; 2&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;puts google_data.to_xml&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Becomes for production use:&lt;br /&gt;&lt;pre lang="ruby" line="1"&gt;&lt;br /&gt;&lt;br /&gt;require 'rubygems'&lt;br /&gt;require 'scrubyt'&lt;br /&gt;&lt;br /&gt;google_data = Scrubyt::Extractor.define do&lt;br /&gt;  fetch "http://www.google.com/ncr"&lt;br /&gt;  fill_textfield "q", "ruby"&lt;br /&gt;  submit&lt;br /&gt;&lt;br /&gt;  link "/html/body/div/div/div/a"&lt;br /&gt;&lt;br /&gt;  next_page "Next",:limit =&gt; 2&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;google_data.to_xml.write($stdout, 1)&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;And outputs:&lt;br /&gt;&lt;pre lang="xml"&gt;&lt;br /&gt;&lt;root&gt;&lt;br /&gt;  &lt;link&gt;http://www.ruby-lang.org/&lt;/link&gt;&lt;br /&gt;  &lt;link&gt;http://www.ruby-lang.org/en/20020101.html&lt;/link&gt;&lt;br /&gt;  &lt;link&gt;http://en.wikipedia.org/wiki/Ruby_programming_language&lt;/link&gt;&lt;br /&gt;  &lt;link&gt;http://en.wikipedia.org/wiki/Ruby&lt;/link&gt;&lt;br /&gt;  &lt;link&gt;http://www.rubyonrails.org/&lt;/link&gt;&lt;br /&gt;  &lt;link&gt;http://www.rubycentral.com/&lt;/link&gt;&lt;br /&gt;  &lt;link&gt;http://www.rubycentral.com/book/&lt;/link&gt;&lt;br /&gt;  &lt;link&gt;http://www.youtube.com/watch?v=JMDcOViViNY&lt;/link&gt;&lt;br /&gt;  &lt;link&gt;http://www.w3.org/TR/ruby/&lt;/link&gt;&lt;br /&gt;  &lt;link&gt;http://www.zenspider.com/Languages/Ruby/QuickRef.html&lt;/link&gt;&lt;br /&gt;  &lt;link&gt;http://poignantguide.net/&lt;/link&gt;&lt;br /&gt;  &lt;link&gt;http://www.rubynz.com/&lt;/link&gt;&lt;br /&gt;  &lt;link&gt;http://www.ruby-doc.org/&lt;/link&gt;&lt;br /&gt;  &lt;link&gt;http://tryruby.hobix.com/&lt;/link&gt;&lt;br /&gt;  &lt;link&gt;http://www.rubycentral.org/&lt;/link&gt;&lt;br /&gt;  &lt;link&gt;http://www.gemstone.org/gem-by-gem/english/ruby.html&lt;/link&gt;&lt;br /&gt;  &lt;link&gt;http://whytheluckystiff.net/ruby/pickaxe/&lt;/link&gt;&lt;br /&gt;  &lt;link&gt;http://intertwingly.net/blog/&lt;/link&gt;&lt;br /&gt;  &lt;link&gt;http://lotusmedia.org/&lt;/link&gt;&lt;br /&gt;  &lt;link&gt;http://www.oreillynet.com/ruby/&lt;/link&gt;&lt;br /&gt;&lt;/root&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;One of the authors showed me a good example which I don't think is linked to from anywhere yet, so &lt;a href="http://scrubyt.org/images/pricegrabber_tutorial.jpg"&gt;here&lt;/a&gt; it is in case you are interested.&lt;br /&gt;&lt;br /&gt;We'll see if this lives up to its promise in real world usage, but looking good so far.  One major drawback is that it breaks on heavy AJAX sites e.g. clicking a paging link which actually loads the next page in place using an ajax call.  However, one can usually find a non-ajax workaround to get to the same data.  The authors are aware of this and planning on integrating somethign like &lt;a href="http://code.google.com/p/firewatir/"&gt;FireWatir&lt;/a&gt; to allow it to handle ajax/dhtml requests in a seamless fashion.&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/9067288001838449347-6681170572567972273?l=simplygenius.com' alt='' /&gt;&lt;/div&gt;</description><link>http://simplygenius.com/2007/06/web-crawling-with-ruby.html</link><author>noreply@blogger.com (Matt Conway)</author><thr:total>0</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-9067288001838449347.post-1120861286087657706</guid><pubDate>Fri, 15 Jun 2007 14:22:00 +0000</pubDate><atom:updated>2008-12-30T14:08:09.246-08:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>Rails</category><title>Custom loggers in rails</title><description>I ran into some problems trying to setup a custom logger in rails which I thought I would share to ease someone else's pain.  Everything I read said that to setup a custom logger instance, I should set config.logger in my environment.rb, e.g.&lt;br /&gt;&lt;code&gt;&lt;br /&gt;environment.rb:&lt;br /&gt;&lt;br /&gt;config.logger = MyLogger.new(config.log_path)&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;However, I just could not get this to have any effect!  It turns out that this was because I was starting up my server using script/server using mongrel.  Using "script/server webrick", or "mongrel_rails start" worked just fine.&lt;br /&gt;&lt;br /&gt;I think this is caused by code in the mongrel.rb file that script/server uses which loads just the logging environment (but not my environment) in order to figure out which log file to tail&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;railties/lib/server/mongrel.rb:&lt;br /&gt;&lt;br /&gt;require 'initializer'&lt;br /&gt;Rails::Initializer.run(:initialize_logger)&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Loading the environment here causes the RAILS_DEFAULT_LOGGER constant to get set, and thus when my config finally gets loaded when mongrel itself starts up, the config.logger I set gets ignored as the rails init code does nothing if RAILS_DEFAULT_LOGGER is set:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;railties/lib/initializer.rb:&lt;br /&gt;&lt;br /&gt;def initialize_logger&lt;br /&gt;  # if the environment has explicitly defined a logger, use it&lt;br /&gt;  return if defined?(RAILS_DEFAULT_LOGGER)&lt;br /&gt;  ...&lt;br /&gt;end  &lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The patch on &lt;a href="http://dev.rubyonrails.org/ticket/7084"&gt;this bug report&lt;/a&gt; seems related, but didn't fix my problem.&lt;br /&gt;&lt;br /&gt;I'm too much a rails newb to figure out the &lt;em&gt;right&lt;/em&gt; way to patch this, hopefully someone with more of a clue will see this blog entry and submit a patch :)&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/9067288001838449347-1120861286087657706?l=simplygenius.com' alt='' /&gt;&lt;/div&gt;</description><link>http://simplygenius.com/2007/06/custom-loggers-in-rails.html</link><author>noreply@blogger.com (Matt Conway)</author><thr:total>0</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-9067288001838449347.post-5170176921983875234</guid><pubDate>Mon, 11 Jun 2007 05:42:00 +0000</pubDate><atom:updated>2008-12-30T14:08:09.220-08:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>Rails</category><title>Life at a Startup (Mobicious)</title><description>So I've been working at &lt;a href="http://www.mobicious.com"&gt;Mobicious&lt;/a&gt; for a week now, and the task list just keeps getting longer :)  Not really surprised by this, as it is a startup.  Is actually kinda cool to have this much to do, especially when most of it is interesting.  I guess that makes me a workaholic. :)&lt;br /&gt;&lt;br /&gt;Of course, being mostly a Java dev at the last job, I'm having to do a lot of reading and catchup on Rails.  We are using Ruby on Rails at mobicious and I can see no overwhelming reason to change this.  Scalability will be a concern eventually, but from all I've read, Rails can scale, just not quite as well as Java yet.  This is not surprising given their relative levels of maturity.  If that hasn't changed by the time we need it to scale hugely (here's hoping), we'll re-evaluate then.  One option will be to switch &lt;em&gt;to&lt;/em&gt; java for running rails, but to do so we'll have to come up with alternatives to binary rails plugins like RMagick.  For now though, I'm sticking with Rails as it does give us an advantage in development time - though not quite there for me personally yet :)&lt;br /&gt;&lt;br /&gt;So far I'm really liking the startup environment, and the people are all really great, the work is interesting, and I'm having fun!&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9067288001838449347-5170176921983875234?l=simplygenius.com' alt='' /&gt;&lt;/div&gt;</description><link>http://simplygenius.com/2007/06/life-at-startup-mobicious.html</link><author>noreply@blogger.com (Matt Conway)</author><thr:total>1</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-9067288001838449347.post-3999631247781812356</guid><pubDate>Wed, 30 May 2007 11:37:00 +0000</pubDate><atom:updated>2008-12-30T14:08:09.198-08:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>Misc</category><title>Farewell TripAdvisor</title><description>Today is my last day working for &lt;a href="http://tripadvisor.com"&gt;TripAdvisor&lt;/a&gt;, where I've spent the last 3+ years working as a senior software engineer with a very talented group of people.   I'm going to miss working with everyone here, but the lure of the startup is just too great :)&lt;br /&gt;&lt;br /&gt;Next stop, is &lt;a href="http://mobicious.com"&gt;Mobicious&lt;/a&gt;, a startup in the mobile space near Waltham, MA (office location still undetermined).  I'll be employee #4, so fun times ahead.  Stay tuned as my adventures unfold.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9067288001838449347-3999631247781812356?l=simplygenius.com' alt='' /&gt;&lt;/div&gt;</description><link>http://simplygenius.com/2007/05/farewell-tripadvisor.html</link><author>noreply@blogger.com (Matt Conway)</author><thr:total>3</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-9067288001838449347.post-614049165654810895</guid><pubDate>Mon, 21 May 2007 19:59:00 +0000</pubDate><atom:updated>2008-12-30T14:08:09.178-08:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>Misc</category><title>Switched to wordpress</title><description>Finally got tired of messing with &lt;a href="http://pebble.sourceforge.net"&gt;pebble&lt;/a&gt;, and decided to give &lt;a href="http://wordpress.org"&gt;wordpress&lt;/a&gt; a try.  Much better!  Only problem is that my permalinks have all changed.  Hopefully I'll figure out a way to map the old permalinks into the new layout - one of the wordpress custom formats gets close, but instead of the leaf being the pebble article id, its the article title - which I do prefer.  I guess I'll have to add in custom rewrite rules for all the old ones. Anyone else have a better idea?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9067288001838449347-614049165654810895?l=simplygenius.com' alt='' /&gt;&lt;/div&gt;</description><link>http://simplygenius.com/2007/05/switched-to-wordpress.html</link><author>noreply@blogger.com (Matt Conway)</author><thr:total>2</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-9067288001838449347.post-8370408807985924318</guid><pubDate>Mon, 21 May 2007 19:30:00 +0000</pubDate><atom:updated>2008-12-30T14:08:09.169-08:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>Uncategorized</category><title>genlibs.sh</title><description>For generating eclipse library files from thirdparty directory structure&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9067288001838449347-8370408807985924318?l=simplygenius.com' alt='' /&gt;&lt;/div&gt;</description><link>http://simplygenius.com/2007/05/genlibssh.html</link><author>noreply@blogger.com (Matt Conway)</author><thr:total>0</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-9067288001838449347.post-542205072766525182</guid><pubDate>Mon, 21 May 2007 18:52:00 +0000</pubDate><atom:updated>2008-12-30T14:08:09.156-08:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>Uncategorized</category><title>About</title><description>Matthew Conway is a software engineer currently working in the Boston area for a &lt;a href="http://www.mobicious.com"&gt;mobile community/directory website&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9067288001838449347-542205072766525182?l=simplygenius.com' alt='' /&gt;&lt;/div&gt;</description><link>http://simplygenius.com/2007/05/about.html</link><author>noreply@blogger.com (Matt Conway)</author><thr:total>0</thr:total></item></channel></rss>
