quick fix for RVM is not a function

January 31st, 2013

I have a lot of Rails apps (1.x, 2.x, and 3.x) and keeping Ruby versions and gem updates correct is difficult. RVM to the rescue. It worked a few days ago (right after installation) but now I keep getting the “RVM is not a function” message, and I’ve tried all of the suggestions at rvm.io. At the moment I’m in too big of a hurry to figure this out, but I tried the solution below and it worked.

If you get the message

RVM is not a function, selecting rubies with ‘rvm use …’ will not work.
You need to change your terminal emulator preferences to allow login shell.
Sometimes it is required to use `/bin/bash –login` as the command.

Please visit https://rvm.io/integration/gnome-terminal/ for a example.

Try this: if you have SSH turned on

ssh your-user-name@localhost
rvm use 1.8.7

Three monitors, CPU spikes, very slow and unresponsive screens

January 28th, 2013

update: this does not seem to work. The easy solution is to just log out and log back in when this problem happens every few days… It could be that I’m running openSUSE 11.4 from a few years ago….

I have a Core i7, 8GB of RAM, and NVidia 9600 GT with 2 outputs driving 2 monitors, and an NVidia GT520 with 1 output driving a 3rd monitor. With 2 monitors, everything was fine and dandy and fast. Adding the 3rd monitor slowed the computer to a crawl, but only if Eclipse, Open Office, or any of a few others were open (and they’re frequently open!!!!).

Running the top command in various scenarios over a few weeks showed that pretty much any Java app would cause XOrg to use 100% of the CPU.

I am running openSUSE 11.4 which I installed a few years ago and have been meaning to upgrade but just haven’t had the time. Perhaps my issue is related to the OS and a few other things being outdated.

Upgrading Java from 1.6 to the latest (1.7) by following the instructions here fixed the problem and my computer is lightning-fast again. The script I used (by following the instructions and carefully* replacing lib with lib64) is here.

*search & replace warning: /usr/lib64/jdk_Oracle/jre/lib should not end with 64 or the script will fail (i.e. a global search for lib and replace with lib64 will not work).

Inline attachments aren’t/weren’t that bad in Rails 1.x and 2.x

May 11th, 2012

I needed to fix an older app today that was written with Rails 1.2.3. It wasn’t sending inline attachments in emails correctly. It was trying to use one of the many gems named something like inline attachment (which may not be suitable for use with older Rails versions), but gave up and did it manually. I decided that it was easier to hand-code the ActionMailer::Part parts of the email than to use a gem designed to make this easier. I think that the app broke when the correct gem was uninstalled and could not be reinstalled (because it was removed from wherever it was published).

class Mailer < ActionMailer::Base
  def postcard
    recipients 'you@yourdomain'
    from       'me@mydomain.com'
    subject    'my email to you'

    image_path = "#{RAILS_ROOT}/public/images/something.jpg"
    base = File.basename(image_path)
    cid = "#{base}@mydomain.com"

    part :content_type => 'multipart/related' do |pt|
       pt.part :content_type=> 'text/html' do |html|
         html.body = "<img src=\"cid:#{cid}\" />"
       end
       attachment :content_type => "image/jpg; name=#{base}" do |a|
         a.headers["Content-ID"]="<#{cid}>"
         a.body = File.read(image_path)
       end
    end
  end
end

Copy a new drawable resource into the drawable folders

April 9th, 2012

There might already be a way to do this, but I could not figure it out. This morning I needed to take an image, resize it four times, and copy it into the eight Android drawable folders (drawable-hdpi, drawable-hdpi-v5, drawable-ldpi, drawable-ldpi-v5, drawable-mdpi, drawable-mdpi-v5, drawable-xhdpi, and drawable-xhdpi-v5). Rather than do that manually, I resized it once for the largest density (xhdpi) and wrote a script to do the rest. This script:

  • assumes that the target image is the correct size for xhdpi
  • resizes it for the lower densities
  • copies the resized image into the drawable folder.

I wanted to name it resize as in resource-ize but that looks like resize as in change-the-size. So I instead named the script rezize. Now I just save the file in the res folder (my_file.png), rezize my_file.png, and then delete the file. It could be more elegant, but this is good enough for me.

#!/bin/bash
# arg 1 is file name
#   - will use identify to get height and width
#   - will assume that the file is the correct dimensions for xhdpi
#   - will do 75% for hdpi
#   - will do 50% for mdpi
#   - will do 37.5% for ldpi

WIDTH=$(identify -format "%w" "$1")
HEIGHT=$(identify -format "%h" "$1")

echo copying $1 to drawable-xhdpi/$1 and leaving size as ${WIDTH}x${HEIGHT}
echo copying $1 to drawable-xhdpi-v5/$5 and leaving size as ${WIDTH}x${HEIGHT}
cp "$1" "drawable-xhdpi/$1"
cp "$1" "drawable-xhdpi-v5/$1"

newwidth=$(echo "$WIDTH*0.75" | bc)
newheight=$(echo "$HEIGHT*0.75" | bc)
echo copying $1 to drawable-hdpi/$5 and making size ${newwidth}x${newheight}
echo copying $1 to drawable-hdpi-v5/$5 and making size ${newwidth}x${newheight}
convert -resize ${newwidth}x${newheight} "$1" "$1.resized"
cp "$1.resized" "drawable-hdpi/$1"
mv "$1.resized" "drawable-hdpi-v5/$1"

newwidth=$(echo "$WIDTH*0.5" | bc)
newheight=$(echo "$HEIGHT*0.5" | bc)
echo copying $1 to drawable-mdpi/$5 and making size ${newwidth}x${newheight}
echo copying $1 to drawable-mdpi-v5/$5 and making size ${newwidth}x${newheight}
convert -resize ${newwidth}x${newheight} "$1" "$1.resized"
cp "$1.resized" "drawable-mdpi/$1"
mv "$1.resized" "drawable-mdpi-v5/$1"

newwidth=$(echo "$WIDTH*0.375" | bc)
newheight=$(echo "$HEIGHT*0.375" | bc)
echo copying $1 to drawable-ldpi/$5 and making size ${newwidth}x${newheight}
echo copying $1 to drawable-ldpi-v5/$5 and making size ${newwidth}x${newheight}
convert -resize ${newwidth}x${newheight} "$1" "$1.resized"
cp "$1.resized" "drawable-ldpi/$1"
mv "$1.resized" "drawable-ldpi-v5/$1"

Getting adb and udev set up on openSUSE

March 6th, 2012

I had a heck of a time getting my development machine to recognize my Droid 2. I could plug in the USB cable, see the drive mounted, and everything seemed to work. But Eclipse would not see it when I tried to run an Android application. Executing adb devices (located in ~/android-sdks/platform-tools) showed that the device had no permissions.

Google created a Using Hardware Devices guide to help get it working, but it doesn’t work as-is — probably because there are so many flavors and releases of Linux.

Google also created a list of vendor IDs which, although helpful, didn’t work because, at least on my machine, the ‘B’ in 22B8 needs to be in lower case.

Below are the steps I went through to get it to work:

First try (no changes were made)

cd ~/android-sdks/platform-tools
./adb devices
List of devices attached
???????????? no permissions

Second try (copying the example in step 3a here and the Motorola code here)
/etc/udev/rules.d/51-android.rules
SUBSYSTEM==”usb”, ATTR{idVendor}==”22B8″, MODE=”0666″, GROUP=”plugdev”

sudo udevadm control –reload
(unplug and plug device)
cd ~/android-sdks/platform-tools
./adb devices
List of devices attached
???????????? no permissions

Third try (removing the GROUP attribute)
/etc/udev/rules.d/51-android.rules
SUBSYSTEM==”usb”, ATTR{idVendor}==”22B8″, MODE=”0666″

sudo udevadm control –reload
(unplug and plug device)
cd ~/android-sdks/platform-tools
./adb devices
List of devices attached
???????????? no permissions

Fourth try (lower-casing the ATTR{idVendor} attribute) — BINGO!
/etc/udev/rules.d/51-android.rules
SUBSYSTEM==”usb”, ATTR{idVendor}==”22b8″, MODE=”0666″

sudo udevadm control –reload
(unplug and plug device)
cd ~/android-sdks/platform-tools
./adb devices
List of devices attached
C70C81FB96E295FE no permissions

Note 1: That’s a made-up device ID. I copied 16 random hex characters from here.
Note 2: Word Press is a PITA and replaces double-dashes with m-dashes. The command to restart udev is udevadm control double-dash-reload
Note 3: I did this on openSUSE 11.4. I have also done it on 12.1 but need to confirm the rule is the same on that other machine.

Querying Google Analytics with Ruby

December 22nd, 2011

A client asked us to show Google Analytics data on one of our sites, so that they would not have to leave our site to get that data. I decided that the best way to do this is to import the requested Google Analytics metrics daily at 3:00 a.m. This way, we query Google Analytics only once per day (rather than on every page request). There is a quota policy on querying Google Analytics data, and this ensures that we don’t come close to filling that quota.

The example below borrows from the Google Analytics curl tester.

There are a few Ruby libraries for accomplishing this task, but my needs were so simple that I preferred to retrieve the XML from Google Analytics and get the metrics from XPath queries.

Google Analytics metrics, request and response, and XML are well-documented.

require 'net/http'
require 'uri'
require 'rexml/document'

http = Net::HTTP.new('www.google.com',443)
http.use_ssl = true

# in order to query Google Analytics, you have to log into Google and acquire an authorization token
path = '/accounts/ClientLogin'
data = {'Email' => 'YOUR_EMAIL',
'Passwd' => 'YOUR_PASSWORD',
'accountType' => 'GOOGLE',
'source' => 'GA-curl-tester',
'service' => 'analytics'}

resp,data = http.post(path,data.to_query)
auth_token = resp.body.split("\n").detect{|x|x=~/^Auth=/}.sub(/^Auth=/,'')

# now use the authorization token get the GA data
data = {'ids' => 'ga:YOUR_ACCOUNT_ID',
'metrics' => 'ga:visitors,ga:pageviews',
'start-date' => '2011-01-01',
'end-date' => Date.yesterday.strftime('%Y-%m-%d')}

path = "/analytics/feeds/data/?#{data.to_query}"
h = {'Authorization' => "GoogleLogin auth=#{auth_token}"}
resp,data = http.get(path,h)
ga_xml_string = resp.body
doc = REXML::Document.new(ga_xml_string)

# you can store these variables in a database or handle them in whatever manner you see fit
ga_visitors=REXML::XPath.first(doc,"//dxp:aggregates/dxp:metric[@name='ga:visitors']").attributes['value']
ga_pageviews=REXML::XPath.first(doc,"//dxp:aggregates/dxp:metric[@name='ga:pageviews']").attributes['value']

Bash script: delta (shows difference between lines of input)

November 17th, 2011

Today, I wanted to take the set:
10
13
15
19

and output the difference between each number and the previous (i.e 13-10, 15-13, 19-15):
3
2
4

What I started with (and didn’t want):

mysql –password=1234 -D stuff -Nse “select myField from myTable”
70636127
70651486
70668927
70678701

What I do want:

mysql –password=1234 -D stuff -Nse “select myField from myTable” | ./delta
15359
17441
9774

I wrote a Bash script (a filter) to do that:

#!/bin/bash
while read line; do
  if [ "$prev" != "" ]; then
    echo $(($line-$prev))
  fi
  prev=$line
done

I did it this way because it’s much cleaner to do it through a filter than it is to do it through the SQL statement. This keeps the SQL statement clean and easy to tweak, and this filter is useful for other purposes such as reading from an input file:

delta < numbers.txt
#this works, too
cat numbers.txt | delta

Send email with multiple attachments from command line

June 27th, 2011

I needed to email a few files to myself from a Linux box. I did not want to use the typical command, which results in two emails:

uuencode file1 | mail -s "your first file" me@mydomain.com
uuencode file2 | mail -s "your second file" me@mydomain.com


I wanted to send them in one email. I tried what’s below, which did not work, because each uuencode command wrote to stdout separately. I ended up with an email only containing second_file.

uuencode file1 first_file && uuencode file2 second_file | mail -s "a bunch of files" me@mydomain.com


Next I tried what’s below, which works, but is just too much code. I prefer one-liners for this sort of thing.

uuencode file1 first_file >> uu.txt
uuencode file2 second_file >> uu.txt
cat uu.txt | mail -s "a bunch of files" me@mydomain.com
rm uu.txt


It turns out that attachments, in an email body, are just concatenated together, so you can chain together the uuencode commands to make an email with multiple attachments.

Notice the parentheses — they’re required, otherwise you’ll only get one file, the last file, as an attachment. The parentheses ensure all of the files are sent to stdout at once (rather than separate instances or processes), and they’re piped to mail as one blob (forgive me if I don’t have my Linux terms correct):

(uuencode file1 first_file && uuencode file2 second_file) | mail -s "a bunch of files" me@mydomain.com


Note that file1 is the name of the file on disk, and first_file is the name of the attachment as it appears in the email

Rotate an image and make it into a sprite

June 3rd, 2011

Today I needed to rotate an image several times and put each rotation it in a sprite. I used ImageMagick’s convert and montage commands. They’re both spectacular tools, and I’ve used less than 1% of their capabilities below. The printf command is naming each file with leading zeroes (e.g. 000.png, 015.png, 030.png, 045.png), and this ensures that they’re named in sequence. Comment out the rm command to see what actually happens.

Here is the image (a rather boring example, I admit):

#!/bin/bash
#make a temp folder
mkdir .tmp

#rotate example-arrow.png across the horizon in 15-degree increments with convert
for i in {0..180..15}
do
  convert -rotate $i example-arrow.png .tmp/$(printf %03d $i).png
  echo rotated $i degrees
done

#make a sprite (a vertical strip) containing all 13 images with montage
montage -tile 1x13 .tmp/*.png sprite.png

#delete the arrows that were shoved into the sprite
rm -rf ./.tmp

And here is the sprite.

Check disk space with threshold, email result, in Linux

May 26th, 2011

A few days ago, my /tmp partition filled up. Oops. It slowly filled up over the course of 11 months. Now, I have a script that emails me when any partition is more than 80% full. I can change the threshold easily.

It uses the df command to print disk usage information, uses sed to trip out the % symbol (not sure that’s necessary — awk seems to treat, say, 25 and 25% equally), then uses awk to output lines that are over the threshold, and then wc sees how many lines awk put out. If awk put out anything, then the threshold was crossed and the output of df will be sent in an email.

#!/bin/bash
threshold=80
if [ "$(df -h | sed 's/%//g' | awk 'NR>1{if($5 > '$threshold') print "WARNING"}' | wc -l)" -gt "0" ]
  then df -h | mail -s "Disk utilization on $(hostname) > $threshold%" me@mydomain.com
fi