Learning Git

I think I finally get git!

Some resources I found useful while learning:

The graphs in Git for Computer Scientists really helped me understand how git works on the inside, which answers a lot of questions about why commands behave as they do.

Git Immersion is a follow-along-style walkthrough covering basic git interactions.

A successful Git branching model describes general branching model practices as applied to git, but uses the --no-ff for all merges.

Understanding the Git Workflow talks about why this is bad and offers alternatives.

I find that GitHub Flow works much better for web development than git-flow.

Other useful links:


How To Fix “_arguments:comparguments:208: invalid argument: ARG” SVN Tab Completion Error

SVN 1.5 changed the Subversion help output to print ARG instead of arg. Unfortunately, the file which ZSH uses to parse the Subversion help output to generate the tab completion options was only looking for a lower case arg. The result is the error _arguments:comparguments:208: invalid argument: ARG when trying to tab-complete svn commands in ZSH.

The fix was committed to the ZSH source in Jan 2008, but still has yet to make its way into all the machines being sold by hosting providers.

If you get stuck with a box with the new SVN but the old ZSH you can fix this yourself by editing /usr/share/zsh/x.x.x/functions/_subversion and replacing




both places it occurs.

VoilĂ ! SVN tab completion works again.

Downloading Podcasts With CRON

I used to open iTunes so I could click the “update” button to get the latest version of a podcast. Then I got tired of waiting for iTunes and decided I could keep my podcasts updated via CRON. Here’s the script I use which should work for most podcasts with an XML feed:

wget --output-document=- --quiet http://feeds.americanpublicmedia.org/MarketplacePodcast | grep mp3 | head -1 | sed -e "s/^.*\(http.*mp3\).*/\1/" | wget --input-file=- --quiet --output-document /tmp/marketplace.`date +\%Y-\%m-\%d`.mp3

Connecting to MS SQL Server with Ruby on Rails


If you’re running the Rails app on a Windows box you’ll first need the the DevKit toolkit in order to build gems:

Regardless of platform you’ll need to install the ODBC Binding for Ruby and SQL Server 2005 and 2008 Adapter For ActiveRecord. Add the latter (at least) to your project by adding config.gem "activerecord-sqlserver-adapter" to your environment.rb config section.


On Linux we’ll need the FreeTDS libraries in order to talk to the MS SQL. You’ll need to add an entry to the freetds.conf file specifying how your database can be reached. Be sure to confirm the installation to make sure it’s possible to connect to the database.

To bridge the gap between Rails and FreeTDS you’ll need to add your database configuration settings to two additional files, /etc/odbc.ini and /etc/odbcinst.ini.

In /etc/odbcinst.ini add something to the effect of:

Description = TDS driver (Sybase/MS SQL)
Driver = /usr/lib64/libtdsodbc.so
Setup = /usr/lib64/libtdsS.so
CPTimeout =
CPReuse =
FileUsage = 1

Make sure the Driver and Setup paths point to the actual libraries.

In /etc/odbc.ini add something to the effect of:

Driver = FreeTDS
Description = ODBC connection via FreeTDS
Trace = No
Servername = SERVER_NAME

Then, in your database.yml file:

adapter: sqlserver
mode: ODBC
username: USER
password: PASS

Customize the all-caps strings as needed, except the mode, which really is ODBC.

Installing Tomcat 6 on a cPanel Server

The cPanel EasyApache system makes it easy to recompile Apache with various add-ons and modules. There’s even a checkbox for adding Tomcat. Unfortunately, this installs Tomcat 5.5, and I needed Tomcat 6.0. Here’s how I got it:

1) install Tomcat 5.5 using EasyApache (see this .pdf for details)

2) download and expand Tomcat 6 in /usr/local/jakarta

3) change the tomcat symlink to point to your new version (i.e. /usr/local/jakarta/apache-tomcat-6.0.XX)

4) from http://trulymanaged.com/blog/installation-of-tomcat6/:

#cd apache-tomcat-6.0.18
# cd bin
# tar xvfz jsvc.tar.gz
# cd jsvc-src
# chmod +x configure
# ./configure
# make
# cp jsvc ..
# cd ..

5) copy over any Host blocks from tomcat/conf/server.xml from the old Tomcat install to the new Tomcat install (you may or may not be able to set up new hosts through WHM)

6) copy over conf/workers.properties from the old Tomcat install to the new Tomcat install

7) start tomcat normally (/usr/sbin/starttomcat)

The /manager/html/ Tomcat manager application doesn’t load, though, so it’s not perfect.

If you ever need your old Tomcat back just stop Tomcat, flip the tomcat symlink back to the old install, and restart Tomcat.

Dreamhost to Google Apps naked domain name redirection

I’ve had this problem twice in recent memory, which warrants taking notes.

Dreamhost has a handy “Google Hosted” feature where with a single click they’ll completely configure your domain to use Google Apps. You can then use Google Sites and the rest of the Apps suite for your entire website. Unfortunately, while Google Sites allows you to map a subdomain to a Google Site page, mapping naked domains (e.g. example.com) are not supported. If one maps the www subdomain to a Google Site then the traditional www.example.com will resolve, but example.com gives a Google-served 404 error. When using the Dreamhost “Google Hosted” feature all of the generated domain DNS records are non-editable, so you’re stuck with an A record which maps the domain to a nonexistent site.

My solution was to not use the Dreamhost “Google Hosted” feature at all, but to instead use the “DNS Only” option. I copied down all the generated DNS entries from the “Google Hosted” setup and manually recreated them, with one exception. The A record for the naked domain I directed to, which is the IP address of WWWizer, a free service which handily redirects any naked domain request the the corresponding www subdomain.

Now I have a site set up on my www subdomain with Google footing the hosting bill, and naked domain requests are seamlessly redirected to the www-based home page.

Enabling chat outside Google Apps

Google Apps users can chat with other users on the Google Talk network, but it’s also possible to set up federation on your domain to allow your users to chat with anyone using the XMPP protocol.

The Google Help page on the topic, at http://www.google.com/support/a/bin/answer.py?hl=en&answer=34143, is pretty weak. “If you require assistance making these changes in your domain host account”, they offer, “we suggest contacting your domain host.”

The change involves adding SRV DNS records for your domain. The records to be added are:

_xmpp-server._tcp.gmail.com. IN SRV 5 0 5269 xmpp-server.l.google.com.
_xmpp-server._tcp.gmail.com. IN SRV 20 0 5269 xmpp-server1.l.google.com.
_xmpp-server._tcp.gmail.com. IN SRV 20 0 5269 xmpp-server2.l.google.com.
_xmpp-server._tcp.gmail.com. IN SRV 20 0 5269 xmpp-server3.l.google.com.
_xmpp-server._tcp.gmail.com. IN SRV 20 0 5269 xmpp-server4.l.google.com.
_jabber._tcp.gmail.com. IN SRV 5 0 5269 xmpp-server.l.google.com.
_jabber._tcp.gmail.com. IN SRV 20 0 5269 xmpp-server1.l.google.com.
_jabber._tcp.gmail.com. IN SRV 20 0 5269 xmpp-server2.l.google.com.
_jabber._tcp.gmail.com. IN SRV 20 0 5269 xmpp-server3.l.google.com.
_jabber._tcp.gmail.com. IN SRV 20 0 5269 xmpp-server4.l.google.com.

where gmail.com is replaced by your apps domain name.

Wikipedia takes a SRV record in the form

_sip._tcp.example.com. 86400 IN SRV 0 5 5060 sipserver.example.com.

and breaks it down thusly:

_Service._Proto.Name TTL Class SRV Priority Weight Port Target


  • Service: the symbolic name of the desired service.
  • Proto: the transport protocol of the desired service; this is usually either TCP or UDP.
  • Name: the domain name for which this record is valid.
  • TTL: standard DNS time to live field.
  • Class: standard DNS class field (this is always IN).
  • Priority: the priority of the target host, lower value means more preferred.
  • Weight: A relative weight for records with the same priority.
  • Port: the TCP or UDP port on which the service is to be found.
  • Target: the canonical hostname of the machine providing the service.

Taking the first of the Google provided record definitions as an example,

_xmpp-server._tcp.gmail.com. IN SRV 5 0 5269 xmpp-server.l.google.com.

we have:

  • Service: xmpp-server
  • Proto: tcp
  • Name: gmail.com.
  • TTL: (none given)
  • Class: IN
  • Priority: 5
  • Weight: 0
  • Port: 5269
  • Target: xmpp-server.l.google.com.

where, again, gmail.com is replaced by your Google Apps domain.

My DNS settings provider doesn’t offer a “Name” field while adding SRV records; instead they have a “Record/Hostname” field where the domain fixed but with the opportunity to enter a subdomain. This is usually not necessary with Google Apps, unless your primary Google Apps domain is actually a subdomain. For me I just left the “Record/Hostname” field blank and the “Name” was set correctly.

You can test that your new SRV records were created correctly using dig:

dig SRV _xmpp-server._tcp.gmail.com

You should get back, in the ANSWER SECTION, just what the Google Help page listed for that service (with a TTL added):

_xmpp-server._tcp.gmail.com. 86400 IN SRV 20 0 5269 xmpp-server1.l.google.com.
_xmpp-server._tcp.gmail.com. 86400 IN SRV 20 0 5269 xmpp-server2.l.google.com.
_xmpp-server._tcp.gmail.com. 86400 IN SRV 20 0 5269 xmpp-server3.l.google.com.
_xmpp-server._tcp.gmail.com. 86400 IN SRV 20 0 5269 xmpp-server4.l.google.com.
_xmpp-server._tcp.gmail.com. 86400 IN SRV 5 0 5269 xmpp-server.l.google.com.

If you don’t want to wait for the DNS updates to propagate you can ask your domains name server directly:

dig @ SRV _xmpp-server._tcp.gmail.com

Where is replaced with the IP address of your domains name server.

Shell Script

A fun little shell script:


DVD Backups

DVD Decrypter faithfully copies disks to drives. Mode ISO > Read will produce an .iso of a disk; a double-layer disk will produce an 8GB .iso. The File mode just copies all the files as-is straight from the disk into a VIDEO_TS folder. DVD Decrypter looks like it can also burn .isos by changing the Mode to ISO > Write, but I haven’t tried it yet.

ImgBurn is great for burning .iso files to a DVD. Just insert a DVD, choose your source file, and click the button.

DVD Shrink will create a 4GB .iso from a double-layer disk!



For encoding for iPhone I like that HandBrake has iPhone presets. Just open the disk, select the preset, and click Start. When it’s done just drag the .m4v into iTunes, sync, and go.

Reusing stdout

stdout is nice–it let’s you see what’s going on. But what if you want to see what’s going on and also do something else with the same output.

tee is useful for redirecting stdout to a file, but what if you want to send the same output to another command too, like mail?

You disguise the command as a file, that’s what. Through process substitution you can say things like

echo "hello world" | tee >(mail -s "notice")

and have the message go to stdout and your mail program. You can chain process substitutions to do as many different things with the same output as you want.

Process substitution is supported in bash and friends, but not, as far as I can see, in sh.

Next Page »

powered by WordPress     themed by Mukkamu     presented by ideaharbor.org     everything else by steve hulet