The Elegant Chaos Blog

July 12, 2005

Looking at my logs, I noticed that I was getting quite a lot of people looking for old links, particularly for Last Exit to Hypercard.

As a result, I’ve put up most of my old site at


June 30, 2005

I’ve updated my Drupal module Autolink to version 1.1.

To use Autolink, you define a Drupal taxonomy and add some terms to it.

When any of these terms occurs in text on your site, Autolink automatically adds an html link to whatever URL you have specified for that term. So, for example, you can enter terms for all of your friends, then any time you refer to them in a post, their names will automatically be linked to their blogs.

The main change in this version is that you can specify some replacement text, so that when the link gets created, the replacement text is displayed instead of the original text.

As an example of why replacement text is useful, say we defined a term “Apple”, to be linked to “”. The danger with this is that an article containing the word “Apple” in another context might inappropriately be linked to the Apple website. We could use a less ambiguous term, like “Apple Computer Inc.”, but we don’t want that text to have to actually appear in all of our articles, because it is unnecessarily formal. The solution is do match for “Apple Computer Inc.” in the article, but provide a replacement that converts it to “Apple” in the final output. Now it’s unlikely to be matched incorrectly, but the text will still read ok.

For more details, see the Autolink project page.


June 27, 2005

Drunken Blog has been talking about byte-swapping, amongst other things, with regard to the Apple x86 issue.

My comment, having done quite a bit of porting games to the mac from the PC, would be that endian issues accounted for a hell of a lot of my problems, especially the hard-to-track-down bugs where some behaviour quietly changed in some obscure part of the game, without anything actually crashing.

The worst thing tended to be when people cast pointers to (void) or (char) in one place, and then accidentally cast them back to the wrong type somewhere else.

Luckily, incorrect code is actually more likely to work on little endian systems than it is on big endian ones.

This is because, if you have a small value stored in a long, and you take a pointer to the long, then treat it as a pointer to a short (or char), then read the value that it’s pointing to, the value will still be correct on a little endian system, provided that the value actually fits into the short (or char).

On a big endian system, you end up pointing to the other end of the value, which gives totally unexpected results most of the time - if you’re lucky and the value was set as its original type, you’ll get a zero. If you’re unlucky, and the pointer code is doing the setting, whilst some other code is reading the value as the original type, you’ll get uninitialised memory.

Obviously, casting pointers to and from (void) and (char) is a bit of a nasty way to behave generally, but there are legitimate reasons for doing it (well, semi-legitimate, if you’re using old skool C library routines), and it’s easy for mistakes to creep in.

So people with dirty code are going to have some trouble with this. The good news is, over all, getting through the problem will leave their code in a much healthier state.


It’s amazing how easily I can get distracted.

Currently my main distraction is playing with Feed Me, my bayesian news filter, which is a thinly veiled excuse to mess about with Python.

However, yesterday I managed to get distracted from that distraction.

I’ve been thinking that I really need to sort out some productivity tools for myself, to deal with the sort of repetitive administrative tasks that I find myself doing again and again.

To that end, I installed FastScripts, and set about writing some trivial scripts to do some simple things.

One of the scripts I wanted was to find all the recent mails received from a particular person, since this is something that I do manually quite often. The script would only save a few keystrokes and mouse clicks, but I figured that if I could link it to a hot key with FastScripts, it would be handy.

Unfortunately, it turns out that Apple Mail’s scripting support doesn’t allow you to perform searches.

Luckily, there is a work around, in the form of the new GUI scripting capabilities of MacOS X.

Essentially, this allows you to ‘fake’ any user interface operation by scripting it in terms of the menus, buttons and or places that you would click, and the keys that you would press.

Presented below, for your delight and delectation, is a little example of how I used this to script a search in Mail.

The hardest part is working out exactly how to specify the interface widget that you’re trying to activate. A valuable helper here is the Prefab UI Browser which allows you to browse another application’s user interface whilst it’s running, so that you can discover the hierarchy of interface widgets.

The bad thing with all of this, of course, is that it’s a very fragile way to program. By relying on the names and layout of particular widgets, the script becomes very likely to break when a new version of Mail comes along with a different user interface. So I wouldn’t recommend it if there is a useable Applescript interface available instead, but it’s bloody handy when there isn’t one!

The key routine here is searchMailboxForMailFrom() which takes the name of a user and a mailbox, and uses them to perform a find in Mail. The assistive devices support that makes all this possible is only available in OS X 10.3 or higher, and the user has to have turned it on in the system preferences, so it’s necessary to check for that if you want to be a well behaved script and fail gracefully when there’s a problem.

on run
	if gotInterfaceScripting() then
		set mailIcon to "/Applications/"
		display dialog "Search for mail from:" with title "Search Inbox" default answer "" with icon POSIX file mailIcon
		if the result's button returned is "OK" then
			searchMailboxForMailFrom("Inbox", the result's text returned)
		end if
	end if
end run

on searchMailboxForMailFrom(searchIn, searchFrom)
	tell application "Mail"
	end tell
	tell application "System Events"
		tell process "Mail"
			-- select first mailbox in list - should be the inbox
			select (first row of outline 1 of scroll area 1 of window 1 whose value of static text 1 is searchIn)
			-- select the "mailbox search" menu item
			click menu item "Mailbox Search" of menu "Find" of menu item "Find" of menu "Edit" of menu bar item "Edit" of menu bar 1
			-- type the search term and hit return
			keystroke searchFrom
			keystroke return
			repeat until exists button searchIn of window 1
				-- can get errors if the script runs before the button has been created...
				-- so we wait here
			end repeat
			-- click the mailbox button (as opposed to searching in all mailboxes)
			click button searchIn of window 1
			-- click the from button to search in the From: field
			click button "From" of window 1
		end tell
	end tell
end searchMailboxForMailFrom

on gotInterfaceScripting()
	if gotPanther() then
		-- check to see if assistive devices is enabled
		tell application "System Events"
			if UI elements enabled then
				return true
			end if
		end tell
		tell application "System Preferences"
			set current pane to ¬
				pane ""
			set the dialog_message to "This script utilizes " & ¬
				"the built-in Graphic User Interface Scripting " & ¬
				"architecture of Mac OS X " & ¬
				"which is currently disabled." & return & return & ¬
				"You can activate GUI Scripting by selecting the " & ¬
				"checkbox “Enable access for assistive devices” " & ¬
				"in the Universal Access preference pane."
			display dialog dialog_message buttons {"Cancel"} ¬
				default button 1 with icon 1
		end tell
	end if
	return false
end gotInterfaceScripting

on gotPanther()
	-- get the system version
	set the hexData to system attribute "sysv"
	set hexString to {}
	repeat 4 times
		set hexString to ((hexData mod 16) as string) & hexString
		set hexData to hexData div 16
	end repeat
	set the OS_version to the hexString as string
	if the OS_version is less than "1030" then
		display dialog "This script requires the installation of " & ¬
			"Mac OS X 10.3 or higher." buttons {"Cancel"} ¬
			default button 1 with icon 2
		return false
	end if
	return true
end gotPanther


June 21, 2005

I’ve been tinkering with CSS and Drupal today, trying to get a better understanding of the theme system.

As a result, I’ve got a new theme as the default on the site. It’s called Heatwave (if you live in London, you’ll understand why I chose that name…) and it’s basically a cleaned up and pared down version of the Croxted theme that I was using before.

I’ve been trying to simplify the design as much as possible, removing duplication in the css and trying to make the whole thing a bit lighter. I’ve also tried to reduce the impact of the tabs (which you generally only see when editing pages).

There are probably still some things wrong or missing, so let me know what you think, especially if you see anything particularly hideous. The old Croxted theme is still available, so if you log in you can switch back to it if you prefer.