Archive for the 'How To' Category

Essential CSS Hacks

You ever have a project where something just won’t render correctly in IE 6 or IE 7, but looks fine in other versions of IE, Firefox, Safari, and so on? Or a situation where your layout looks great in Firefox, but quirks in IE, and quirks in a completely different way in Safari? Yeah, story of my life.

Then I discovered Essential CSS Hacks. This is by far the simplest reference I’ve come across for the various ways you can cause only one particular browser to see a CSS definition. Sure, it would be great if hacks like these weren’t necessary, but because there are no reference implementations for any of the W3C standards, how can anyone truly be taken to task?

That is all. I now return you to your regularly scheduled nerding.

Boy, Is My Face Red

So then I discovered that the functionality I was trying to add to bsflite was kinda, sorta, maybe already there. Way to read the entire help output, smart guy.

That left only a couple of features I really wish bsflite had. One is more robust tab completion, such that screennames could be partially completed out to the next difference, the way bash does it. Another is deleting the last word on the line with Ctrl-W, also the way bash does it. I’m in love with bash, you know.

Since I’m about as good at C programming as Stevie Wonder would be at tennis, I thought that if I wanted to tackle one of those features, I’d have to go with the easier one. So, Ctrl-W word deletion it is!

I jumped the gun on the thing and had a semi-working prototype up and running, which I posted to the project page on Sourceforge just before realizing that it is full of bugs. Back to the drawing board I went, writing a test harness and experimenting with pointers and strings until I was really pretty darn sure it would work.

At which point it did not work.

As it turns out, the third time is the charm, and I really think I’ve gotten it to a workable stage. I was able to make it segfault once, but I haven’t yet figured out what caused it to do that, so for what it’s worth, here it is. Without further ado…

The bsflite 0.82 word delete patch

The Joys of AIM

AOL Instant Messenger is really the last remaining shred of AOL’s former monopoly. Once folks realized that they didn’t need AOL to get on the Internet, and that the Internet itself, through search engines and portals, could give them basically the same stuff they got from AOL for at least half the price, they dumped that service like a ton of bricks. In their scramble to rebuild the empire they once enjoyed, AOL introduced AOL Instant Messenger, which has now become completely entrenched in the world of instant messaging.

Despite the alternatives, including the big names like Yahoo!, MSN, and Google, not to mention Jabber, etc., most people mean AIM when they say “IM.” That being the case, huge numbers of third-party clients have been released to give access to the AIM network from other platforms and using different interfaces. In OS X, Adium takes the cake. For Windows there’s Trillian. In Linux, of course, gAIM. But if you want to use a console client (because it makes you three times as 1337), you have a choice.

The forerunner in the console AIM client race is nAIM (I believe it is short for ncurses AIM, invoking the name of the console input/output library it uses, ncurses). But I have had spotty luck with it myself, either because it’s in a development rut or because of my particular system setup. nAIM crashes a bit for me and so on. On top of that, it’s very friendly and colorful, but that doesn’t work for everyone in every situation.

So I found “bsflite,” a very lightweight client written in C that compiles on most *NIX platforms (check the bsflite Sourceforge page for more). I started using it and I like it very much. It’s fast, it’s simple, it gets the job done. Except for one thing…

The basic interface concept of bsflite is a simple prompt with all other messages and status information dumped into the screen from bottom to top. In order to send messages and do other things, you enter a single-character command followed by any parameters. For example, to send an IM, you enter “m” followed by the user’s screenname. There is some tab-completion, but it only works once you’ve typed enough of a name to be unique and on top of that, if you are talking with just one person, you have to type at least the first few letters of their name over and over.

So I came up with a pretty simple solution that allows you to press tab on an empty line to pop up the command to send a message to the last person you sent a message to. In other words, if you enter “mfavoritefriend How do you do?” and then press tab on a blank line, you will get “mfavoritefriend” with a space after it so you can enter another message.

The change was really simple, so if anyone uses bsflite and wants to hook it up, here is the patch

This patch is for bsflite 0.82. Other versions may not be quite the same and the patch is for the main file, bsf.c, so be wary of that.

Getting Your Web 2.0 on, iPhone Style

Long has it been since a post was made here; my apologies. Last week I totally snapped and bought an iPhone despite the modest litany of reasons I thought I shouldn’t (locked to one carrier, not standard GSM, battery life qualms, questionable extensibility) and my overall reaction is do it. If you are a smart and resourceful person, as I am sure you are since you are reading this blog, you will have no trouble bending the iPhone to your whims. This is one such report.

Lately, I’ve been Twittering (yes, it’s a verb now, too). For those of you who aren’t in the know, Twitter is a service that allows you to send a text message reporting, simply, what you are doing. That text message is then displayed on Twitter’s site (if you so desire), but is also relayed via SMS to any other Twitter users who are “following” you. Likewise, you receive text messages from Twitter when people you are “following” send in their updates.

The whole thing is a little bit silly, but the reported effect is to have a better peripheral idea of your friends’ daily lives and circumstances without having to hassle them synchronously (a little Web 2.0 lingo for you there). Thus, when you run into so-and-so, you may remember that they recently crashed their car or that they saw some movie you wanted to see, and so on. It’s not important information, but it’s neat.

So there I was, Twittering my heart out, when I realized that more of my friends read Facebook on a daily basis than participate in Twitter, and that Facebook provides an interface for updating your “status,” which is printed next to your picture on your profile page and disseminated through the “news feed.” Obviously, I could not stand idly by and let Twitter be updated but not Facebook! Ruby to the rescue.

The first step was to build an interface to Facebook’s status updating system, which is not supported in their public API (for shame). Because there is no programming interface for it, I had to make my script access the page through normal HTTP methods, forge the login security of the browser and cookies, and post the update that way. Here is the code:

require 'net/http'
require 'net/https'
require 'cgi'

def StatusFacebook(status,opt)
   if not opt.is_a? Hash or (not opt.has_key? 'user' or not opt.has_key? 'pass')
      return false
   end

   ua = opt.has_key?('ua') ? opt['ua'] : 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.4) Gecko/20060612 Firefox/1.5.0.4 Flock/0.7.0.17.1'
   post_headers = {
      'Content-Type' => 'application/x-www-form-urlencoded',
      'User-Agent' => ua
   }
   get_headers = {
      'User-Agent' => ua
   }

   http = Net::HTTP.new('www.facebook.com')
   response = http.request_get('/login.php', get_headers)

   challenge = response.body.match(/<input[^<]*?name="challenge".*?>/)[0].match(/value="(.*?)"/)[1]

   loginform = "email="+CGI.escape(opt['user'])+"&pass="+CGI.escape(opt['pass'])+"&challenge=#{challenge}&md5pass=&next="

   cookies = []
   response.get_fields('Set-Cookie').each do |c|
      co,k,v = c.match(/^(.*?)=(.*?);/).to_a
      if ['test_cookie', 'login', 'reg_fb_ref', 'reg_fb_gate'].include? k
         cookies << co
      end
   end

   post_headers['Cookie']  = cookies.join(' ')
   get_headers['Cookie']      = cookies.join(' ')

   http = Net::HTTP.new('login.facebook.com', 443)
   http.use_ssl = true
   http.verify_mode = OpenSSL::SSL::VERIFY_NONE

   response = http.request_post('/login.php', loginform, post_headers)

   if response.code == '302'
      cookies = []
      response.get_fields('Set-Cookie').each do |c|
         co,k,v = c.match(/^(.*?)=(.*?);/).to_a
         if ['test_cookie', 'login', 'login_x', 'xs', 'c_user', 'h_user'].include? k
            cookies << co
         end
      end

      post_headers['Cookie']  = cookies.join(' ')
      get_headers['Cookie']      = cookies.join(' ')

      get_headers['Referer'] = 'https://login.facebook.com/login.php'
      get_headers.delete('Referer')
      http = Net::HTTP.new('www.facebook.com')

      response = http.request_get('/home.php?', get_headers)

      if response.code == '200'
         post_form_id = response.body.match(/<input[^<]*?id="post_form_id".*?>/)[0].match(/value="(.*?)"/)[1]

         if not post_form_id.empty?
            statusform = 'status=' + CGI.escape(status) + '&post_form_id=' + post_form_id

            post_headers['Referer'] = 'http://www.facebook.com/home.php'
            response = http.request_post('/updatestatus.php', statusform, post_headers)

            if response.body.match(/#{status}/)
               return true
            else
               return false
            end
         end
      end
   end

   false
end  

Feel free to pick through it. The important part to notice is the handling of the authentication cookies. I used the “Live HTTP Headers” Firefox Add-In to trace the headers during a Facebook login, took note of the cookies required, and selected only those cookies to be transmitted. Facebook has some pretty slick security measures as well, including a “challenge” code that is generated on the login form and checked along with your authentication information, and a “post_form_id” value that appears within every link and form post on the front page of the site, presumably to further validate the session integrity. There are a couple of neat .match() lines to capture those.

Step two was to access Twitter. Twitter does have an API, which is accessed through REST (for Twitter’s interface, that’s just a fancy shmancy term for “post a form”). Here is the Ruby function for updating Twitter:

require 'net/http'
require 'cgi'

def StatusTwitter(status,opt)
   if not opt.is_a? Hash or (not opt.has_key? 'user' or not opt.has_key? 'pass')
      return false
   end

   ua = opt.has_key?('ua') ? opt['ua'] : 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.4) Gecko/20060612 Firefox/1.5.0.4 Flock/0.7.0.17.1'
   post_headers = {
      'Content-Type' => 'application/x-www-form-urlencoded',
      'User-Agent' => ua
   }
   get_headers = {
      'User-Agent' => ua
   }

   response = Net::HTTP.post_form(URI.parse('http://'+CGI.escape(opt['user'])+':'+CGI.escape(opt['pass'])+'@twitter.com/statuses/update.xml'),
                                          { 'status' => status } )

   return true if response.code == '200'
   return false
end  

Then there is bootstrap code that calls those two functions. Hooray. So what about the iPhone, then?

Well, thanks to the iPhone’s nearly complete and rather robust support for e-mail, I decided to create a way for my home mail server to receive a message and use it to update the status on those sites. From there, the possibilities would be endless. All I needed was a little procmail recipe to check that the message was addressed to my status-update address and a little script to process the full e-mail message and run the update. Here is the procmail destination file that bootstraps the updates:

#!/usr/bin/env ruby

BASEPATH = __FILE__.match(/^.*\//)[0]

require "#{BASEPATH}status_twitter"
require "#{BASEPATH}status_facebook"
require 'net/smtp'

$stdin.each do |line|
   if subject = line.match(/^Subject:(.*?)$/)

      # Format the subject.
      status_fb = subject[1].strip
      status_tw = subject[1].strip
      # No initial cap for Facebook.
      status_fb[0] = status_fb[0].chr.downcase
      # Initial cap for Twitter.
      status_tw[0] = status_tw[0].chr.upcase

      ret_fb = StatusFacebook(status_fb, {
         'user' => 'your_user_name',
         'pass' => 'your_password'
      })
      ret_tw = StatusTwitter(status_tw, {
         'user' => 'your_user_name',
         'pass' => 'your_password'
      })

      ret_fb = (ret_fb) ? 'Success' : 'Failure'
      ret_tw = (ret_tw) ? 'Success' : 'Failure'

msg = <<EOF
From: Status <my.status.email@my.domain>
To: iPhone <my.iphone.acct@my.domain>
Subject: Update report

I have submitted your update, "#{status_tw}"

Facebook: #{ret_fb}
Twitter:  #{ret_fb}
EOF
      
      Net::SMTP.start('my.mail.server') do |smtp|
         smtp.send_message msg,
                        'my.status.email@my.domain',
                        'my.iphone.acct@my.domain'
      end
      exit 0
   end
end

exit 0  

I just set procmail to deliver the message to that script if it matched my updater address (by using :0, no flags). That means I never receive e-mail to that address in my actual mail client, which is good. The script also returns an e-mail to my phone to let me know it succeeded because it would take me too long to figure out if it did or not through mobile Safari.

One of the cool things that this script also does is to capitalize the first letter of the update for the Twitter version and lowercase the first letter of the Facebook version. This is done because Facebook builds a sentence like “Aaron is “, while Twitter simply posts the sentence it is entirety. Being a slut for grammar, I require that capitalization and punctuation flow like a river. One also must keep in mind the point-of-view and temporal sense in which the update is written.

I have a plan to make the system handle Facebook updates even more cleverly by replacing “my” with “his” and things like that, though I might be biting off more than I can chew with that one.

Cool, huh?

Editing Textile in VIM

I love Textile. All of my blogs use Textile. In some cases I have even extended Textile to provide additional features, making it a simple matter to add programmatically complex functions with a few extra characters.

Sometimes, though, I like to write my articles off-line and post them later. When I do, I typically use either TextMate in OS X, or Vim (wherever I am, sometimes in an SSH session). Unfortunately, though, there isn’t a lot of support for Textile in VIM. But after a little Googling, I found some.

About a year and a half ago, Dominic Mitchell posted his own Textile syntax file for Vim on his blog. I snapped it up and started using it. There is a slight problem, though, in the way it handles Textile URLs. Apparently thanks to the regex pattern for URL strings lifted from RFC 2396, it allows spaces in URLs, which causes the highlighting to continue after the URL ends.

I’ve applied a fix to the script and posted it here in case anyone (other than me) is actually interested in this sort of thing. Thanks much to Dominic Mitchell for creating this syntax file in the first place; I was not relishing the thought of diving in and creating one myself.

Revised Textile syntax file for VIM

If you wish to use the *.textile extension, as TextMate does, to indicate which files contain Textile syntax, you will want to add the following line to your filetypes.vim, which is located wherever your ftplugin directory is located (on my machine it’s /usr/share/vim/vim62/, but it will be different per-installation and wildly different in Windows):

au BufNewFile,BufRead *.textile setf textile  

Bash Pattern Matching and Replacement

Bash is my favorite shell by far. I have known an occasional csh or tcsh aficionado, and I’m sure that those shells have their own virtues, but for me, bash is the end-all be-all of command line interfaces. Come with me now as I wax nerdy all over bash’s pattern matching capabilities.

At work, I often have to make changes to a number of files that all have the same name, but that are stored in a variety of different folders. The challenge is quickly uploading all of these changed files to the server. Because they are in different folders, I would normally have to drag them, one at a time, into the FTP client.

My solution was to write a bash script that would pull these files together into a “staging” folder on my local drive, mirroring the directory structure they live in so that I can drag the entire tree into my FTP client and let it do its work. I know ahead of time what the directory names will be; they are numbers representing the sites. Here is what a typical folder structure might look like:

ROOT
    folder_1
        660
            folder_2
                file.txt
        671
            folder_2
                file.txt  

What I want to be able to do is simply indicate that I want all of the file.txt files to be staged onto my hard drive and have bash go and find the 660, 671, etc. folders based on their numbers and copy them. This is probably more background information than you need to appreciate the bash tricks I’ve used, but it helps to know what on Earth the script is supposed to do.

The concept of the script is to take a list of files (with relative paths) and for each one try to find one of the preemptively known site numbers in our list. Once we know that number, we can loop through all of the numbers, replacing the original number with each new one and using those generated paths to copy the files to my local drive. That way, we end up with a copy of each file that lives in a structure containing each of the numbers in our list.

For me, the challenge was knowing how to evaluate the matching and stem the paths directly within bash. I wanted to avoid writing this in Ruby and I also wanted to avoid doing a lot of shell execution to run things like tr or awk. Here is the code (implemented as a bash function):

export SITES="660 671 672 685 730 761"

function stagefile() {
  if [ -z "$1" ]; then
    echo "You must provide a file or files to stage."
    return 0
  fi

  for file in $*; do
    for site in $SITES; do
      if [[ "$file" == *$site* ]]; then
        FILESITE="$site"
      fi
    done

    for site in $SITES; do
      NEWFILE="${file//$FILESITE/$site}"
      NEWDIR="${NEWFILE%/*}"
      cp -v --parents "$NEWFILE" "/c/Staging"
    done
  done
}  

The first little bash gem that I discovered is the ability to use the [[ ... ]] syntax to perform a string matching test. When you use the == operator, the right side is used as a pattern to match against the left side using bash “glob” syntax. In this example, I am just checking each site number to see if it occurs within my original path. If and when I find one of them, I save it in FILESITE.

The next step is to loop through all of the site numbers. With each one, I replace all occurrences of the originally found number with the current one, use that path to go find a file and then copy it to my local drive using cp’s parents switch, which causes cp to create directories as necessary to duplicate the structure.

The trick to parents is that the destination must be a directory, so I also use bash replacement to trim off the filename from the path given (as well as the trailing forward slash).

The replacement trick I used is ${file//$FILESITE/$site}, which will take the contents of $file and replace all occurrences of $FILESITE with the value of $site. The syntax is reminiscent of good old fashioned s//, and the first double slash simply means “replace all.” A single slash there would only replace the first occurrence (from left to right).

Then, to remove the file from the end of the path, I used ${NEWFILE%/*}, which takes the contents of the variable $NEWFILE and removes the part that matches /*. There are two forms of this replacement operation: the first uses a percent sign (as in my example) and searches from the end of the string, whereas the second uses a number (or pound or hash) sign and searches from the beginning. Using a single symbol is non-greedy and using two of them is greedy. So, to summarize, %/* searches from the end of the string and non-greedily removes characters. The pattern starts with a forward slash, so it stops matching when it comes to the last forward slash in the string.

I can demonstrate some of these techniques using a little bash interactive example:

$ MYFILE="/usr/local/share/temp.txt"
$ echo $MYFILE
/usr/local/share/temp.txt
$ echo "${MYFILE%/*}"
/usr/local/share
$ echo "${MYFILE%%/*}"

$ MYFILE="usr/local/share/temp.txt"
$ echo "${MYFILE%%/*}"
usr  

I think this replacement functionality is one of the least-known and most commonly useful tricks in anyone’s bash toolbox and I’m surprised at how little coverage it receives in the “bash scripting primers” out there. Most useful is the ability to make sure that a given path does or doesn’t end with a trailing slash, which is instrumental in concatenating paths, especially when dealing with user-supplied arguments.

Let’s say you will receive a path fragment as an argument and you need to append a filename to the end of it, but you don’t know whether the fragment will end with a slash. Here’s how you might do it:

function appendpath() {
  echo "${1%/}/file.txt"
}  

Of course, this function will not work correctly if the user-supplied path ends with a whole string of forward slashes, but it handles the two main use cases: one slash or no slashes. The replacement simply says “remove a slash from the end of the variable called 1,” which does nothing if the slash isn’t there. Then you can confidently add your own slash and the filename. Give it a try!

Resolve 750 Domains in One Line

Let’s say, just for example, that you have a (*NIX-formatted) text file filled with 750 domain names and you want to resolve them all to IP addresses. Let’s also assume that you’re using Windows XP and you have access to Cygwin but that’s about it. Cygwin apparently doesn’t have dig yet, so you’re forced to use nslookup. What do you do?

First, let’s take a look at the output of nslookup when you resolve a single domain.

$ nslookup www.slashdot.org
Non-authoritative answer:
Server:  dnsr1.sbcglobal.net
Address:  68.94.156.1

Name:    www.slashdot.org
Address:  66.35.250.151  

Okay, that’s a multi-line answer. Looking through the man page, I couldn’t find a way to limit the output to the IP address, so we’ll have to use bash trickery to make it happen. You’re smart people, here’s my solution with absolutely no ado.

nslookup www.slashdot.org 2>&1 | grep Address | tail -1 | awk '{print $2}'  

I had to use the 2>&1 piece because (apparently) the “Non-authoritative answer:” portion of the output is printed to STDERR. Why? Who knows. Using 2>&1 gloms the STDERR output onto STDOUT so it can be filtered out by the following grep. Then, tail -1 to get the last “Address” line printed, and then awk to print the address rather than the heading.

But wait, there’s trouble! Try Google:

$ nslookup www.google.com
Non-authoritative answer:
Server:  dnsr1.sbcglobal.net
Address:  68.94.156.1

Name:    www.l.google.com
Addresses:  64.233.161.147, 64.233.161.99, 64.233.161.103, 64.233.161.104
Aliases:  www.google.com  

Our grep statement will still catch the “Addresses” line, but now the IPs have commas between them, which awk will include in its output (because it’s tokenized by spaces), so we’ll have to do away with the commas.

nslookup www.slashdot.org 2>&1 | grep Address | tail -1 | tr ',' ' ' | awk '{print $2}'  

The new tr command will translate commas into spaces, allowing awk to properly snag the IP. This gives us a single command that will take in a domain name and output an IP address (provided that nslookup succeeds). How do we feed it an entire text file? Let’s presume that our file is called domains.txt.

for i in `cat domains.txt`
    do nslookup $i 2>&1 | grep Address | tail -1 | tr ',' ' ' | awk '{print $2}'
done  

If you were running this on the command line rather than in a script, you’d want to put semicolons between the lines (or hit \ to continue input on the next line). Provided that the input file is formatted as *NIX text, for i in will pass one line at a time into the body of the block. Pretty sweet, right? Redirect the output of that whole statement into another text file and you’ll have your list of IPs!

Per-Site Styles in Firefox

I try very hard not to be a buzzkill; my cynical personality makes it hard for me not to trash talk things that offend my sense of aesthetics, but if I did that whenever I felt the urge, I fear I’d never do anything else. As a web developer in 2007, as much as it pains me to say so, there is still an awful lot to feel queasy about.

You don’t see a lot of “under construction” graphics around these days, let alone animated ones, so at least we have that to be thankful for. We have certainly come a long way since:

www.geocities.com/city/alley/dumpster/MYHOMEP~1.HTM

Still, the Internet—as most other places as well, unfortunately—is riddled with tasteless, colorblind people. Fortunately for those of us who are total hardcore nerds, even other people’s lack of taste doesn’t have to affect our web browsing experience thanks to a little something called (or at least, what I call) per-site styles. Continue reading ‘Per-Site Styles in Firefox’