09.27.07
Hacking your signature file (baseball bragging rights division)
I wanted to blog about this for a while, and suddenly it’s almost too late. I hacked together some stuff to put the Red Sox’ magic number for clinching the American League East division in my e-mail signature automatically. The process is replicable for any kind of updating content.
About the magic number
In case you’re still confused, the magic number for a team in first place is a countdown to the “clinching” or mathematical assurance of the championship. Every time the team in first place wins, the number goes down. Every time the team in second places loses, the number goes down. When the number reaches zero, the race is over.
The race is clinched when the first place team is more games ahead of the second-place team (and all the other teams) than the number of games remaining. So one way to define the magic number is the lead in the standings, minus the number of games remanining, plus one or rounded up in the case of half-game differences in the standings. What amounts to the same thing, however, is the total number of games in the season, minus the number of wins by the first-place team, minus the number of losses by the second place team, plus one. It’s clear by that last definition that it does what you want (goes down with each win by first-place team or loss by second-place team), and the number of games plus one makes it reach zero at the point of clinching.
The Red Sox have been in first place in the AL East since April, and although they have been in first place a lot, they have not finished the division in first place since 1995. I’ve had the magic number in my signature since it was in the 60s (shortly after the all-star break), and today it stands at two. Which means the division could be clinched today.
Generating the content
The idea is simple: write a script which visits an internet location of baseball standings and munge that data to get the magic number. There are tons out there, such as every newspaper’s website or the megasites like EPSN. Scrolling through source code of Dashboard widgets I found out that MLB publishes this data in a lightweight, machine-readable format on a secret page. Today’s AL East standings can be found at
http://mlb.com/components/game/year_2007/month_09/day_27/standings_rs_ale.js
This file has lots of standings data in the form of a JavaScript object. This is really useful if you’re writing a JavaScript program to display the standings. XML would have been another choice, but this is just as easy to parse, maybe even easier. Also, this resource includes the magic number, not that your script couldn’t calculate it for you. Here’s an excerpt from the file:
var standings_rs_ale = [{
w: '94',
elim: '-',
rs: '850',
div: 'ale',
gameid: '2007_09_27_minmlb_bosmlb_1',
status: 'P',
pre: null,
last10: '5-5',
onerun: '22-26',
xtr: '2-5',
nextg: '9/27 v MIN, 7:05P',
vsW: '20-17',
ra: '643',
gb: '-',
wrap: '/news/wrap.jsp?ymd=20070926&content_id=2231984&vkey=wrapup2005&fext=.jsp&c_id=mlb',
home: '49-28',
code: 'bos',
pct: '.595',
league_sensitive_team_name: 'Boston',
vsC: '20-11',
vsE: '42-30',
vsR: '69-41',
vsL: '25-23',
xwl: '99-59',
strk: 'W2',
l: '64',
lastg: '9/26 v OAK, W 11-6',
interleague: '12-6',
team: 'Boston',
road: '45-36'
}, ...
There’s one of these records for each team in the division. The “elim” key is the magic number to be eliminated, so the Red Sox’ magic number can be found as the “elim” value for the second-place team.
I wanted to write this part of the program in python. I like perl, too, but I’ve been flummoxed trying to re-read my own perl scripts after setting them aside for a while. Python is hyper-strict on syntax but that makes it pretty easy to read.
Seeing the page in JavaScript made me think of JSON, a data-interchange format similar to JavaScript syntax. I thought parsing the JavaScript data in python would be as easy as reading it and hitting it with a python JSON library. Not quite. The standings page is valid JavaScript but not valid JSON. But rather than write my own parser I decided to massage the included JavaScript string so that it did parse as JSON. A little quoting of key values, switching double and single quotes, and getting rid of html links did that trick.
So here’s my script, which I saved as ~/Library/Scripts/getmn.py:
#!/sw/bin/python
# Get the Red Sox magic number
import cjson, re, urllib, datetime
today=datetime.date.today()
mlburl=”http://mlb.com/components/game/year_%04d/month_%02d/day_%02d/standings_rs_ale.js” % (today.year,today.month,today.day)
rawdata=urllib.urlopen(mlburl).read(-1)
(varname,data) = rawdata.split(’=',1)
# although this data is legal javascript, it’s not JSON. So we have
# to munge it a bit:
# quote property names with double quotes
data=re.compile(”\t([a-zA-Z0-9_]+):”,re.M).sub(’\t”\\1″:’,data)
# get rid of links
data=re.compile(”<a[^>]*>|</a>”).sub(”",data)
# replace single quotes by double quotes
data=data.replace(”‘”,’”‘)
dd=cjson.decode(data)
if (dd[0][’team’]==’Boston’):
print “Red Sox magic number: %d” % (int(dd[1][’elim’]))
What I like about this script is that it does very little lifting of its own, farming out most of the retrieval, data-crunching, and parsing. Even the massaging is done with ultra-powerful (as a class, not to say that mine are) regular expressions. This script works on the command-line if that’s all you want.
Adding the content to the sig
I use Microsoft Entourage for reading my mail and keeping calendar and contact info. I’m not in love with it but it is AppleScriptable, so you can do a lot with it. I wrote an AppleScript to run my magic-number-getter and append it to my standard “work” signature (that has my title, address, and a link to my vCard file in it):
set theScript to quoted form of POSIX path of (path to home folder as string) & “Library/Scripts/getmn.py”
set crlf to (ASCII character 13)
tell application “Microsoft Entourage”
set txt to do shell script theScript
set defaultSig to the content of the first signature where name is “Harvard”
set theSig to the first signature where name is “Harvard + Red Sox”
set the content of theSig to defaultSig & crlf & crlf & txt
end tell
AppleScript is a pain in the rear to write—it takes a lot of trial and error. But once it’s done, it reads pretty well. The crlf’s just insert blank lines.
If you have a different mail reader, this is going to change. But I’m confident the idea will work in Apple’s Mail.app as well.
Automatically updating
I saved this script in the folder ~/MIcrosoft User Data/Entourage Script Menu Items/ as “Get Red Sox Magic Number for Signature” So it’s accessible within the Script menu of Entourage.
But the final feature I wanted was to have that information update automatically. Entourage also has a scheduler, so I configured a job to run this script once a day:


That’s it! The workflow is easily copied for whatever oft-changing data you would want in your signture (for instance, the output of /usr/bin/fortune).
PS: While researching this post I found a site (with various different URLS) that computes the magic number for you and gives you HTML widgets. Plus a lot of Google ads, but useful all the same.
technorati tags:applescript, python, microsoft, entourage, baseball, hacks
Blogged with Flock
Keith said,
March 25, 2008 at 1:56 pm
The site that you linked to is mine.
I wrote my calculator in PHP. I do pretty much the same thing you did for all the MLB teams, not just the Red Sox. It kicks off March 31, and checks every hour from 12PM to 1AM (I don’t want to stress the host site). Instead of using the elim number, I use a brute force approach to sort the divisions and calculate the magic number as: 163 - team wins - next in ranking losses (if a first place team this is 2nd place team’s losses, if not first it is first place team’s losses). This is a little different. I haven’t thought about it much but it strikes me that you had better check that you are calculating the magic number correctly if the Red Sox are ever in first place (unlikely as this may be).
My method assumes that all teams have played the same number of games and it breaks due to schedule issues and delayed games, but eventually catches up.
I am sorry about the ads, but I am a capitalist in my own small way. I make the equivalent of case a beer a month off the sites during the regular season. Personally, I browse using Firefox with the AdBlock plug-in and I never see ads, Google or otherwise, unless I am testing one of my own sites. This speeds up web access quite a bit and improves my web experience at the expense of not funding all the other capitalists out there.
Blog: http://www.cthreepo.com/blog