<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"><channel><atom:link rel="hub" href="http://tumblr.superfeedr.com/" xmlns:atom="http://www.w3.org/2005/Atom"/><description></description><title>They told me to.</title><generator>Tumblr (3.0; @justingreer)</generator><link>http://blog.justingreer.com/</link><item><title>Pretty accurate instructions, for today…</title><description>&lt;img src="http://27.media.tumblr.com/tumblr_kug9j1OmmX1qzoloao1_500.jpg"/&gt;&lt;br/&gt;&lt;br/&gt;&lt;p&gt;Pretty accurate instructions, for today…&lt;/p&gt;</description><link>http://blog.justingreer.com/post/277798270</link><guid>http://blog.justingreer.com/post/277798270</guid><pubDate>Thu, 10 Dec 2009 12:47:25 -0600</pubDate></item><item><title>Experience with 1and1...</title><description>&lt;p&gt;I recently received an invoice for a domain renewal from 1and1.com — however, I never asked for the domain to be renewed, nor had any expectation that it would be.  In fact, when I first purchased the domain, I specifically was purchasing it for a single year and didn’t get the impression that my billing information would be stored on their servers.&lt;/p&gt;
&lt;p&gt;I’ll freely admit that they sent an email about a month and a half ago that said they’d be auto-renewing the domain.  However, the subject was “1&amp;1 domain renewal notification,” and glancing at it, I read “The domains listed below are due to expire in 42 days on [date].”  Since I knew I had not requested an automatic renewal I simply ignored the email so that the domain would expire.&lt;/p&gt;
&lt;p&gt;So anyway, I called ‘em up and asked about it, and they said they could send a link to a refund/cancel form.  Which of course I assumed would be an online form behind secure authentication that would let me simply take care of it all.  Instead, it was a link to a PDF that I was supposed to fill out and mail or fax in.  And they wanted my account information, credit card information, &lt;b&gt;and&lt;/b&gt; a copy of a government-issued photo ID.  So considering that I already lost all trust in the company due to the way they charged me for a renewal and stored my billing info without me realizing it, there’s certainly no way I would send them all that information together, especially in a completely insecure manner. (Later another customer support representative told me he doesn’t believe the copy of the ID is necessary, but the form says you have to include it.)&lt;/p&gt;
&lt;p&gt;The second customer support representative I talked to put me on hold and transferred me to the cancellations department without asking me first — “I’ll have to transfer you to cancellations [click]”…  Talking to someone in cancellations (who of course says they have no ability to deal with refunds), she actually asked me to verify my password for her &lt;i&gt;over the phone&lt;/i&gt;.  I wasn’t about to do that, but it decreased my trust of them even further.&lt;/p&gt;
&lt;p&gt;So having hit complete dead-ends with their customer support folks, who say that I agreed in the first place to auto-renewal, and that they can’t refund the charge without me mailing/faxing that form, I gave up and decided to just cancel my account, eating the $9 for the renewal.  (Side note: the first year was $7 — having it auto-renew at a higher rate is one more reason I don’t trust them.)  Unfortunately, when I requested that they delete all my personal, private billing information from their servers after I cancel (because they have no right to store it without my consent), the representative told me that it’s not possible to delete such information from their system.  (!!!)&lt;/p&gt;
&lt;p&gt;The only way to cancel the account is to look up in their FAQ that you go to cancel.1and1.com to process cancellations, which I did.  Of course, then, it makes you go through an email verification (sending a link in email) to verify the cancellation.  However it also says that they won’t process your cancellation until you print, sign, and mail/fax another form to them (albeit a simpler one than the refund form).  I have a hard time believing they stay in business, except for all the charges they receive from people who didn’t want an auto-renew, and haven’t gone through the ordeal of cancelling.&lt;/p&gt;
&lt;p&gt;So, if you’re thinking of buying a domain from 1and1.com, make sure you read all the fine print, and make sure you really want it to auto-renew (at whatever rate they decide is appropriate for subsequent years), and be prepared for some hassle if you ever want to cancel your account.&lt;/p&gt;</description><link>http://blog.justingreer.com/post/174130117</link><guid>http://blog.justingreer.com/post/174130117</guid><pubDate>Fri, 28 Aug 2009 15:04:07 -0500</pubDate></item><item><title>Tab Completion for EC2 Domains</title><description>&lt;p&gt;&lt;br/&gt; Little-known unix command: &lt;i&gt;complete&lt;/i&gt;&lt;br/&gt;&lt;br/&gt; At least for the bash shell, this command controls the &lt;a href="http://www.gnu.org/software/bash/manual/bashref.html#Programmable-Completion"&gt;programmable tab-completion&lt;/a&gt;, allowing you to configure certain programs so their tab-completion only matches files, dirs, some arbitrary set of terms, etc.&lt;br/&gt;&lt;br/&gt; A common example is to set up “svn” so that bash knows its commands, and tab-completes them for you.  A very simplistic version would be like the following:&lt;/p&gt;
&lt;pre&gt;  complete -W "add blame checkout commit copy delete diff log revert status switch update" svn&lt;/pre&gt;
&lt;p&gt;&lt;br/&gt; Granted, for brevity I left out a lot of commands, including their shortened versions, etc.  However it turns out it’s pretty cool, because then you can type “svn u” and hit tab, and suddenly it’s got “svn update” in there for you, rather than trying to match filenames.&lt;br/&gt;&lt;br/&gt; Of course, that brings up an interesting issue — you probably want to match a directory or filename for the second argument…  And if you want to get crazy, &lt;i&gt;complete&lt;/i&gt; lets you do that by passing it a shell function that returns possible completions for the current situation.  There’s a whole package out there with specialized functions for common unix commands, which you can find at &lt;a href="http://www.caliban.org/bash/."&gt;http://www.caliban.org/bash/.&lt;/a&gt;&lt;br/&gt;&lt;br/&gt; However, this blog post is about abusing the tab-completion to match certain domain names.  Existing EC2 instances, that is.  At work we use DynDns to provide a dynamic domain name to each of our EC2 instances, and of course we often want to ssh into them by the dynamic names rather than the default Amazon ones, which look like “ec2-67-123-123-123.compute-1.amazonaws.com”.  For that, first of all, we need to figure out which domain names are currently being used by instances.&lt;br/&gt;&lt;br/&gt; That’s done with a combination of parsing IP addresses out of the data returned from ec2-describe-instances, and looking up the current IP addresses of each of our dynamic domain names.  The ec2 IP parsing looks kinda’ like this (in Ruby):&lt;/p&gt;
&lt;pre&gt;  running_ips = []&lt;br/&gt;&lt;br/&gt;  `ec2-describe-instances`.each_line { |line|&lt;br/&gt;&lt;br/&gt;    running_ips &lt;&lt; $1.gsub('-','.') if line =~ /\bec2-([0-9-]+)/&lt;br/&gt;&lt;br/&gt;  }&lt;/pre&gt;
&lt;p&gt;&lt;br/&gt; The domain lookup is only marginally more complicated…&lt;/p&gt;
&lt;pre&gt;  domains = ("001".."010").collect { |n| "server-#{n}.example.com" }&lt;br/&gt;&lt;br/&gt;  domain_lookup = {}&lt;br/&gt;&lt;br/&gt;  `dig #{domains.join(' ')}`.each_line { |line|&lt;br/&gt;&lt;br/&gt;    domain_lookup[$2] = $1 if line =~ /^\s*(server-\d+\.example\.com).+?\s+IN\s+A\s+([\d.]+)/&lt;br/&gt;&lt;br/&gt;  }&lt;/pre&gt;
&lt;p&gt;&lt;br/&gt; And then we can get a list of currently running domains by pulling the relevant slice of IPs from domain_lookup, and excluding any nils:&lt;/p&gt;
&lt;pre&gt;  running_domains = domain_lookup.values_at(*running_ips).compact&lt;/pre&gt;
&lt;p&gt;&lt;br/&gt; Printing that out looks something like this:&lt;/p&gt;
&lt;pre&gt;  &gt;&gt; puts running_domains.join(' ')&lt;br/&gt;&lt;br/&gt;  server-001.example.com server-002.example.com server-004.example.com&lt;/pre&gt;
&lt;p&gt;&lt;br/&gt; So … Coming back to the bash completion, we could put all that in a script and then do something of this sort:&lt;/p&gt;
&lt;pre&gt;  complete -W '$(ruby ec2_domain_lookup.rb)' ssh&lt;/pre&gt;
&lt;p&gt;&lt;br/&gt; But of course, that’d limit ssh’s tab-completion to only these servers, and would leave out useful things like the username, etc.  Helping that, however is the fact that I’ve already got two aliases in my profile for working with ec2 boxes:&lt;/p&gt;
&lt;pre&gt;  alias ec2='ssh -i ~/.ec2/ssh-keypair -o StrictHostKeyChecking=no -o ServerAliveInterval=240 -l root'&lt;br/&gt;&lt;br/&gt;  alias escp='scp -i ~/.ec2/ssh-keypair -o User=root'&lt;/pre&gt;
&lt;p&gt;&lt;br/&gt; These let me connect to an ec2 box with “ec2 &lt;i&gt;hostname&lt;/i&gt;” or scp files to it with “escp &lt;i&gt;file&lt;/i&gt; &lt;i&gt;hostname&lt;/i&gt;:” (assuming you get the path to your keypair correct, etc.)&lt;br/&gt;&lt;br/&gt; So coming back to the tab-completion, we finally get this:&lt;/p&gt;
&lt;pre&gt;  complete -W '$(ruby ec2_domain_lookup.rb)' ec2&lt;/pre&gt;
&lt;p&gt;&lt;br/&gt; And then since the escp command should also include directories and filenames in its completion, we use the following for it:&lt;/p&gt;
&lt;pre&gt;  complete -W '$(ruby ec2_domain_lookup.rb)' -d -f escp&lt;/pre&gt;
&lt;p&gt;&lt;br/&gt; So that’s the basics…  The next step is to set it up so you always have those available in your shell, and don’t have to wait 10-15 seconds for all the IP/domain lookups to complete, as it generates the completion lists.  So I have a cron job that periodically runs the lookup script, and outputs a file with the two &lt;i&gt;complete&lt;/i&gt; commands in it.  My .bash_login script just sources the file like so:&lt;/p&gt;
&lt;pre&gt;  . ~/.ec2_tab_completion_commands&lt;/pre&gt;
&lt;p&gt;&lt;br/&gt; And it’s always available without delays.  Enjoy.  :)&lt;/p&gt;</description><link>http://blog.justingreer.com/post/94927227</link><guid>http://blog.justingreer.com/post/94927227</guid><pubDate>Fri, 10 Apr 2009 14:02:00 -0500</pubDate><category>ruby</category><category>unix</category><category>tech</category><category>ec2</category></item><item><title>Photo</title><description>&lt;img src="http://27.media.tumblr.com/0npY3KuBXhujlz5xsabp4PUCo1_500.jpg"/&gt;&lt;br/&gt;&lt;br/&gt;</description><link>http://blog.justingreer.com/post/66462195</link><guid>http://blog.justingreer.com/post/66462195</guid><pubDate>Tue, 23 Dec 2008 14:17:06 -0600</pubDate></item><item><title>Finally!</title><description>&lt;p&gt;Google Labs Gmail features are finally integrated into Google Apps for your Domain accounts!  Yay!  Yay!&lt;/p&gt;</description><link>http://blog.justingreer.com/post/63112302</link><guid>http://blog.justingreer.com/post/63112302</guid><pubDate>Thu, 04 Dec 2008 20:20:18 -0600</pubDate></item><item><title>More Backtracing</title><description>&lt;p&gt;Related to the &lt;a title="Backtraces from Live Ruby Processes" href="http://blog.justingreer.com/post/43431342/backtraces-from-live-ruby-processes"&gt;earlier post&lt;/a&gt; on doing backtraces, I figured out how to make some portions work on the Mac version of ruby and/or gdb, so you can do it even when you can’t easily capture stdout…&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;$ gdb -p &lt;process_id&gt;&lt;br/&gt;call (int)rb_eval_string(“$_old_stdout, $stdout = $stdout, File.open(‘/tmp/ruby-debug.’ + Process.pid.to_s, ‘a’); $stdout.sync = true”)&lt;br/&gt;call (int)rb_eval_string(“puts caller.join(\”\\n\”)”)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Yay.  Now it’ll throw the backtrace into a file in your tmp dir.  I’m assuming the same would still work on linux or other unix variants, too.&lt;/p&gt;</description><link>http://blog.justingreer.com/post/55477886</link><guid>http://blog.justingreer.com/post/55477886</guid><pubDate>Mon, 20 Oct 2008 13:27:05 -0500</pubDate></item><item><title>"Your mind is precise and discriminating."</title><description>“Your mind is precise and discriminating.”&lt;br/&gt;&lt;br/&gt; - &lt;em&gt;Fortune cookie…&lt;/em&gt;</description><link>http://blog.justingreer.com/post/46360031</link><guid>http://blog.justingreer.com/post/46360031</guid><pubDate>Sun, 17 Aug 2008 22:56:24 -0500</pubDate></item><item><title>A Tale of Two Batteries</title><description>&lt;p&gt;We all know that laptop batteries lose some of their capacity over time. Apple generally warrants them for a year, if I remember correctly, but after that you’re on your own if the battery barely holds a charge.  But how do you get real info on your battery, other than doing time comparisons?&lt;br/&gt;&lt;br/&gt;Luckily the Mac provides some fairly detailed info.  There’s an application called &lt;a title="coconutBattery" href="http://www.coconut-flavour.com/coconutbattery/index.html"&gt;coconutBattery&lt;/a&gt; that will display this for you, but personally I prefer to grab it from the command line (the same way coconutBattery gets its info).&lt;br/&gt;&lt;br/&gt;I have an alias set up, called “battery”:&lt;/p&gt;
&lt;blockquote&gt;$ alias battery=’ioreg -w0 -l | grep Capacity | cut -d ” ” -f 17-50’&lt;br/&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;br/&gt;This just sets it up so when you type “battery”, it asks the mac to list off a bunch of info and looks for the lines talking about “Capacity” (and then strips off some extra whitespace).&lt;br/&gt;&lt;br/&gt;So here are two examples, from different batteries:&lt;/p&gt;
&lt;blockquote&gt;$ battery&lt;br/&gt;“CurrentCapacity” = 4388&lt;br/&gt;“LegacyBatteryInfo” = {“Capacity”=4388,”Voltage”=12583,”Flags”=5,”Current”=4388,”Amperage”=131,”Cycle Count”=152}&lt;br/&gt;“DesignCapacity” = 5500&lt;br/&gt;“MaxCapacity” = 4388&lt;br/&gt;&lt;br/&gt;$ battery&lt;br/&gt;“CurrentCapacity” = 1608&lt;br/&gt;“LegacyBatteryInfo” = {“Capacity”=1925,”Voltage”=12260,”Flags”=7,”Current”=1608,”Amperage”=12,”Cycle Count”=102}&lt;br/&gt;“DesignCapacity” = 5500&lt;br/&gt;“MaxCapacity” = 1925&lt;br/&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;br/&gt;Basically this shows the current capacity (charge), max capacity, and the capacity the battery was designed for.  The LegacyBatteryInfo line has some other useful info, like flags that tell whether the power cord is plugged in, if the battery is currently charging, and the number of complete recharge cycles the battery has effectively been through.&lt;br/&gt;&lt;br/&gt;What’s interesting here is to see that the first battery is still doing pretty well — it currently can store about 80% of its original charge (4388/5500).  That’s after 152 cycles (and approximately a year of use).  The other battery is a pathetic example, which holds 35% of what it originally could have, after only 102 cycles (and being used less than the other battery over the course of the year).  Personally I’d call it a manufacturing defect, but unfortunately being a bit more than a year old, Apple won’t take responsibility for it.&lt;/p&gt;</description><link>http://blog.justingreer.com/post/45839440</link><guid>http://blog.justingreer.com/post/45839440</guid><pubDate>Wed, 13 Aug 2008 13:06:00 -0500</pubDate></item><item><title>Mallards Game</title><description>&lt;img src="http://26.media.tumblr.com/0npY3KuBXc56a5ydrreBFgde_500.jpg"/&gt;&lt;br/&gt;&lt;br/&gt;&lt;p&gt;Mallards Game&lt;/p&gt;</description><link>http://blog.justingreer.com/post/44410732</link><guid>http://blog.justingreer.com/post/44410732</guid><pubDate>Fri, 01 Aug 2008 21:51:13 -0500</pubDate></item><item><title>Photos of the LHC</title><description>&lt;a href="http://www.boston.com/bigpicture/2008/08/the_large_hadron_collider.html"&gt;Photos of the LHC&lt;/a&gt;: &lt;p&gt;via &lt;a href="http://simonwillison.net/2008/Aug/1/lhc/"&gt;http://simonwillison.net/2008/Aug/1/lhc/&lt;/a&gt;&lt;/p&gt;</description><link>http://blog.justingreer.com/post/44380093</link><guid>http://blog.justingreer.com/post/44380093</guid><pubDate>Fri, 01 Aug 2008 15:24:00 -0500</pubDate></item><item><title>Sending specific traffic over a VPN connection on OSX</title><description>&lt;p&gt;For a while I’ve had to go back and forth between using the “Send all traffic over VPN connection” setting and not using it.  Generally I want the setting off, so that all my network traffic doesn’t get slowed down as it bounces through extra servers.  However, sometimes I need to access computers in the office that aren’t on the default VPN subnet.&lt;/p&gt;
&lt;p&gt;Recently I found this link: &lt;a href="http://blog.liip.ch/archive/2006/01/07/changing-default-routes-on-os-x-on-vpn.html%C2%A0"&gt;http://blog.liip.ch/archive/2006/01/07/changing-default-routes-on-os-x-on-vpn.html &lt;/a&gt; which describes how to tweak the routing settings.  However, it’s a bit out of date; as of that writing, any time you used the built-in VPN setup, all traffic would go over the connection.&lt;/p&gt;
&lt;p&gt;In any case, let’s say you have a VPN where the default subnet is 192.168.2.x but some servers are on 192.168.3.x addresses.  When you connect to the VPN, requests to 192.168.2.x addresses work just fine, but trying to access the others ends up trying to send the requests over the Internet, which of course won’t work.&lt;/p&gt;
&lt;p&gt;To fix this, create a file called &lt;b&gt;/etc/ppp/ip-up&lt;/b&gt; and put the following in it:&lt;/p&gt;
&lt;blockquote&gt;
&lt;pre&gt;#!/bin/sh
/sbin/route -n add -net 192.168.3 $IPREMOTE &gt;&gt; /tmp/ppp.log 2&gt;&amp;1&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;You’ll need to create the file as root, and then set it executable.  Next time you connect to your VPN, the system will automatically run that file, having set the IPREMOTE environment variable to the IP address of the VPN gateway server.  It will make a log of these changes in &lt;b&gt;/tmp/ppp.log&lt;/b&gt; for future reference.&lt;/p&gt;
&lt;p&gt;This tells your computer to always try routing 192.168.3.x addresses through that gateway.  And you can stop sending *all* your network connections through the VPN.  :)&lt;/p&gt;
&lt;p&gt;When you disconnect from the VPN, it automatically removes the route, so you shouldn’t need to do any other cleanup.&lt;/p&gt;</description><link>http://blog.justingreer.com/post/44372540</link><guid>http://blog.justingreer.com/post/44372540</guid><pubDate>Fri, 01 Aug 2008 13:53:28 -0500</pubDate></item><item><title>"top" for filesystem usage...</title><description>&lt;p&gt;Does your mac sometimes slow down to a crawl due to hard drive usage, and you can’t tell what’s causing it?&lt;/p&gt;
&lt;p&gt;I whipped up a little ruby script to act like “top” for filesystem usage.&lt;/p&gt;
&lt;blockquote&gt;
&lt;pre&gt;#!/usr/bin/env ruby

data_read = ''
process_times = Hash.new(0.0)

# Clear screen
print 27.chr + '[2J'

# Open a pipe to fs_usage for file calls.
data = IO.popen('fs_usage -wf filesys')

while true

  # Keep responsive to fs_usage output by reading 10 times per second.
  10.times do
    sleep 0.1

    data_read &lt;&lt; data.read_nonblock(1048576) rescue ''
    lines = data_read.split("\n",-1)
    data_read = lines.pop.to_s

    lines.each do |line|
      elapsed,process = line[138..148],line[152..-1]
      process_times[process] += elapsed.to_f
    end
  end
  
  # Jump up to the top of the screen and print the header.
  print 27.chr + '[f'
  puts "PROCESS".ljust(30) + ' ' + 'TIME'
  puts "------------------------------ ---------"

  # Print in order of which used the most time.
  process_times.sort { |a,b| b[1] &lt;=&gt; a[1] }[0..19].each do |name,time|
    puts name[0,30].ljust(30) + ' ' + sprintf('%0.6f',time).rjust(9,'0')
  end

  # Clear the times for the next loop.
  process_times.each_key { |k| process_times[k] = 0.0 }

end
&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;However, it uses “fs_usage” to get the data, which has to be run as root, so:&lt;/p&gt;
&lt;p&gt;$ sudo ruby fs_top.rb&lt;/p&gt;
&lt;blockquote&gt;
&lt;pre&gt;PROCESS                        TIME
------------------------------ ---------
ruby                           00.000542
pppd                           00.000145
firefox-bin                    00.000000
iTunes                         00.000000
update                         00.000000
cron                           00.000000
thunderbird-bin                00.000000
notifyd                        00.000000
SystemUIServer                 00.000000
&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;Then just hit ctrl+c to quit.  Enjoy.&lt;/p&gt;</description><link>http://blog.justingreer.com/post/44260495</link><guid>http://blog.justingreer.com/post/44260495</guid><pubDate>Thu, 31 Jul 2008 16:46:55 -0500</pubDate></item><item><title>I'm just sayin'...</title><description>&lt;p&gt;Cheetahs Never Lose: 8&lt;br/&gt;Ring of Fire: 9&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.sandlotsports.biz/leagues/teamview.asp?teamId=1254&amp;leagueid=144"&gt;http://www.sandlotsports.biz/leagues/teamview.asp?teamId=1254&amp;leagueid=144&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;:)&lt;/p&gt;</description><link>http://blog.justingreer.com/post/43881163</link><guid>http://blog.justingreer.com/post/43881163</guid><pubDate>Mon, 28 Jul 2008 21:05:37 -0500</pubDate></item><item><title>Ruby 1.8.5, REXML, and You</title><description>&lt;p&gt;In my &lt;a target="_self" title="previous post" href="http://blog.justingreer.com/post/43431342/backtraces-from-live-ruby-processes"&gt;previous post&lt;/a&gt;, I mentioned that I was trying to track down why our mongrels (running Rails) at work were spinning out of control for no apparent reason.  However, finally being able to generate a backtrace from those mongrels led right to the issue.&lt;/p&gt;
&lt;p&gt;The relevant portion of the backtrace looked like this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;from /usr/lib/ruby/1.8/rexml/encoding.rb:59:in `check_encoding’&lt;br/&gt;from /usr/lib/ruby/1.8/rexml/source.rb:40:in `initialize’&lt;br/&gt;…&lt;br/&gt;from /usr/lib/ruby/1.8/rexml/document.rb:45:in `initialize’&lt;br/&gt;…&lt;br/&gt;from ./current/config/../vendor/rails/actionpack/lib/action_controller/cgi_ext/cgi_methods.rb:53:in `parse_formatted_request_parameters’&lt;br/&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So apparently REXML was the culprit, and it was happening while trying to parse the parameters that were passed to our Rails app.  Before any of our (non-framework) code was even called.  From some of my investigation, I knew some of the spinning mongrels corresponded to requests with 200k or more of POST data, so this made some sense.  But other requests with that much data went through just fine.&lt;/p&gt;
&lt;p&gt;In any case, tracking down that line revealed this code, as part of what REXML uses to detect the encoding of the XML data:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;str =~ /^\s*&lt;?xml\s*version=([‘”]).*?\2\s*encoding=([“’])(.*?)\2/um&lt;br/&gt; return $1.upcase if $1&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And, well, that’s just wrong.  The non-escaped question mark, the two “\2” backreferences, the “return $1” instead of “return $3”, etc.  However, our servers are currently running on Ruby 1.8.5.  So I took a look at the corresponding code in the version of REXML that comes with Ruby 1.8.6, and found that it’s fixed:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;str =~ /^\s*&lt;\?xml\s+version\s*=\s*([‘”]).*?\1\s+encoding\s*=\s*([“’])(.*?)\2/um&lt;br/&gt; return $3.upcase if $3&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So it just happens that the sequences of data we were receiving in the rails app were playing unkindly with the broken regular expression, going exponentially out of control with backreferences.&lt;/p&gt;
&lt;p&gt;Changing the old REXML code to the new code brought encoding-detection time down to 52 microseconds instead of 2 *hours* on some of the test data.  So, we fixed that on our servers, and the problem is gone.&lt;/p&gt;
&lt;p&gt;Another solution: Upgrade to Ruby 1.8.6 or better.  :)&lt;/p&gt;</description><link>http://blog.justingreer.com/post/43816903</link><guid>http://blog.justingreer.com/post/43816903</guid><pubDate>Mon, 28 Jul 2008 09:43:47 -0500</pubDate></item><item><title>Backtraces from Live Ruby Processes</title><description>&lt;p&gt;We had some out-of-control mongrel processes at work recently…  They wouldn’t respond to anything except a “kill -9”, were taking 100% cpu time, and spinning for hours before responding to any new requests.&lt;/p&gt;
&lt;p&gt;Unfortunately we had no idea what could be causing it, either.  Loading up gdb and printing out a backtrace only gives a bunch of “rb_call” type entries, the C-level code rather than anything at the ruby level.  The obvious solution is to go ask Google how to get a backtrace.&lt;/p&gt;
&lt;p&gt;Presumed answers:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://weblog.jamisbuck.org/2006/9/22/inspecting-a-live-ruby-process"&gt;http://weblog.jamisbuck.org/2006/9/22/inspecting-a-live-ruby-process&lt;/a&gt; and &lt;a href="http://eigenclass.org/hiki.rb?ruby+live+process+introspection"&gt;http://eigenclass.org/hiki.rb?ruby+live+process+introspection&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;However, they must have been working with a different version of Ruby, because that doesn’t work on my local Mac or the Linux servers; I just get errors about accessing invalid memory.  So after a few frustrating hours I downloaded the source code for Ruby 1.8.6, and found rb_backtrace().  It’s a function that takes no arguments, and prints a backtrace to stdout rather than trying to return an array (which would be semi-difficult to interpret in gdb).&lt;/p&gt;
&lt;p&gt;So …&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;$ gdb -p &lt;process_id&gt;&lt;/p&gt;
&lt;p&gt;(gdb) call (int)rb_backtrace()&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Forces ruby to print a backtrace out to the process’ stdout.  In our case, that’s a daemontools log file, so I could finally track down what was making the mongrel spin forever!&lt;/p&gt;
&lt;p&gt;There’s probably still a great way to do this within gdb, so you don’t have to go find the stdout, or possibly get debug data where it shouldn’t be.  But it’s a starting point.&lt;/p&gt;</description><link>http://blog.justingreer.com/post/43431342</link><guid>http://blog.justingreer.com/post/43431342</guid><pubDate>Thu, 24 Jul 2008 16:19:00 -0500</pubDate></item></channel></rss>
