And now it’s all this I just said what I said and it was wrong. Or was taken wrong. Tue, 26 Aug 2014 01:46:38 +0000 en-US hourly 1 It’s just a silly phase I’m going through Tue, 26 Aug 2014 01:46:37 +0000 I saw Guardians of the Galaxy this past weekend and really enjoyed it. There were a few clunky spots, and I have no idea why people are praising Vin Diesel’s voicing of Groot,1 but it was a fun movie. The movie was not, however, about my Guardians of the Galaxy.

Here are my Guardians, straight outta 1975:

Guardians of the Galaxy

Steve Gerber wrote the Guardians stories during my comics collecting days. I was a big Gerber fan back then, and read everything of his I could get my hands on. I have no idea what Marvel plans to do with Howard the Duck, but (Spoiler Alert!) I assume his appearance at the end of the movie was a nod to Gerber’s work on the old Guardians. Or maybe it was just a recognition that a racoon wasn’t the first anthropomorphic animal hero.

One of the old Guardians did make it into the movie. See the blue-skinned guy with the red fin coming out of his head? That’s Yondu, he of the whistle-controlled yaka arrows. Same blue skin but with a bar on top of his head instead of a fin. And the comic book Yondu didn’t have Michael Rooker’s menacing southern accent, probably because he was from Centauri IV.

The token Earthling, Vance Astro2 (in the blue and white outfit), like Peter Quill, left Earth in 1988, but he wasn’t abducted. Astro volunteered. He was put in suspended animation, bundled into a rocket, and shot to Alpha Centauri in a poorly thought-out attempt to save the human race. In the 1988 of 1975, we were all dying of cancer because we’d destroyed the ozone layer.3 How was one man alone supposed to start a colony on another world? Beats the hell out of me.

Marvel didn’t even think to give Astro an awesome mixtape, because predicting rockets to Alpha Centauri was easier than predicting the Walkman. You’d think they could’ve at least given him an 8-track player.

  1. Bradley Cooper’s Rocket Racoon, on the other hand, deserves every bit of acclaim it’s received. 

  2. Yes, Vance Astro. 

  3. As I recall, Marvel used ozone depletion to explain Killraven’s future Earth, too. 

]]> 0
Better work diary actions Mon, 25 Aug 2014 03:37:47 +0000 In the update at the beginning of this post that shouldn’t have been written, I show how the Launch Center Pro work diary actions should have been built, but I’d like to have a freestanding post describing the actions that I can refer to later. This will be that (somewhat redundant) post.

The LCP actions I use for common entries in my work diary leverage the Drafts action I first described in this post.

Drafts work diary action

This action takes the current time and the contents of the active draft and appends it to a Dropbox file named for the current day. It differs slightly from the original version of the action in that I now use a 24-hour clock for the timestamps.

The diary file that results looks something like this:

Leaving home

At site

Leaving site

At office

Because it’s in Dropbox, I can refer to it from any device.

My most common entries have to do with travel, so I created a set of Launch Center Pro actions to make those entries with a single tap/swipe. They’re in an LCP group entitled Diary:

LCP work diary group

Each action is defined in pretty much the same way. Here’s the one for Leaving Home:

Launch Center Pro diary action

The URL is this:


The only difference between the various diary entry actions is the text= part. The x-success portion at the end causes my screen to return to LCP when the action is done.

I switched to these simple actions from my messy Pythonista scripts on the suggestion of David Cross. Had I waited a little longer, I could’ve just copied an action written by Greg Pierce instead of writing them from scratch. Still, it was heartening to see that what I came up with was basically the same as Greg’s example—that meant I’d finally done it right.

I do think, though, that I can improve the actions a bit. Not by editing the URLs, but by customizing the icons. Because they’re all currently using the default icon for Drafts actions, they all look the same except for their titles, which are too small for me if I’m not wearing my reading glasses. I’m going to look around for public domain icons that will make them more distinct.

Update 8/25/14
A few readers have asked about using geofencing to automatically make entries for leaving and arriving at home and work. I thought about doing that as I was making the actions but decided against it. My work diary isn’t meant to be a tool for tracking my life. As popular as that sort of thing is nowadays, I have no interest in it. I use the diary to account for time I can bill my clients and nothing else. You might say that automatically adding entries I can’t bill for doesn’t hurt, but I don’t agree. With my current system, every entry is relevant when I’m generating a bill after a trip; with an automatic system, the great majority of the entries would be irrelevant, and I would waste time sifting through them.

]]> 0
Work diary revisited Thu, 21 Aug 2014 06:09:20 +0000

Update 8/21/14
You can pretty much ignore this post unless you want to explore the psychology of how someone can get caught in one way of thinking and miss something as plain as the nose on his face.

My first instinct is to write scripts, and I knew I could write Pythonista scripts to do what I wanted. But I didn’t want to have to launch Pythonista to run the scripts, because that would involve a lot of scrolling and would cost more time than they saved. I knew, though, that I could create home screen shortcuts that would run each script with a single tap. You’ll note that there’s no thought of using Launch Center Pro at this point. Although I bought LCP a while ago, I never got into using it.

After making the home screen shortcuts, I found that running a script that way would leave me in Pythonista. Because there’s no URL scheme for Springboard, I couldn’t script in a way to go back to the home screen where the icons lived. I really didn’t want to have to press the home button to get out of Pythonista.

That was when I hit upon using Launch Center Pro, and I was happy because everything worked. But I should’ve realized that LCP, combined with the Work diary action I’d already built in Drafts, could do what I wanted with very simple actions like this:


Not only is this far, far simpler than the Pythonista scripts described below, it runs faster and is more flexible. Later today, I’ll write a much shorter post about using LCP actions like this to create common diary entries.

In the meantime, read what’s below only if you want to look at a case study in complicated foolishness.

The work diary I outlined in this post last year continues to serve me well, but I’ve been looking for more efficient ways to make common entries. After a few attempts that weren’t as helpful as I’d hoped, I think I’ve hit on a solution using a combination of Pythonista and Launch Center Pro.

To review, my work diary is a set of text files stored in a Dropbox folder named “Diary.” Each file is named according to the date, like 2014-08-20.txt, and contains timestamped entries that look like this:

Started 200 degree test

Ended 200 degree test

Started 300 degree test

These entries are created in Drafts. I type or dictate the text of what I’m doing into a blank draft, invoke the Work diary action,

Drafts diary entry

and a new timestamped entry is added to the day file. The Drafts action that does the work is defined this way,

Drafts work diary action

where the file name is


and the template for the entry is


This is a slight change from what I started with last year. Back then, the timestamp used a 12-hour clock with an AM/PM marker. I’ve since changed to a 24-hour clock to make it easier to figure out how much time I spent on each activity.

I don’t have the patience or the discipline to track all my time this way, but I have found this system especially useful on days when I travel. On these days, the entries tend to take on a few common forms:

Leaving home

At site

Leaving site

At office

Because I usually make these entries in my car with the Bluetooth connection on, the ambient noise and car speakerphone make Siri dictation less than perfect. To avoid dictation errors, I set up some shortcuts using the builtin iOS Settings. I soon learned that while shortcuts work fine when they’re part of a longer batch of text, they leave you hanging when the shortcut is the only thing you type.

Shortcut expansion

The little autocorrect bubble just sits there until you either type something else or tap somewhere in the text field.

TextExpander snippets are better for standalone entries because they expand immediately, with no need for additional typing or tapping. So I made a series of snippets for the entries I found myself making again and again.

lhz  -> Leaving home
lwz  -> Leaving work
lsz  -> Leaving site
lhoz -> Leaving hotel
ahz  -> At home
awz  -> At work
asz  -> At site
ahoz -> At hotel

I used these snippets for months, and they never gave me any trouble. Still, it seemed as though the sequence of

  1. Open Drafts
  2. Type abbreviation
  3. Tap action button
  4. Tap Work diary action

was too much for something as routinized as entering canned text like this, especially when my thumbs mistyped the abbreviation and I had to back up and retype. Autocorrect never wanted to turn “adz” into “asz” for me.

So I started thinking about ways to automate these entries further, and Pythonista seemed like my best bet.1 What I ended up with was a series of eight scripts—one for each of the common entries—that I run from Launch Center Pro.

Launch Center Pro shortcuts

A single tap on one of these icons switches me to Pythonista, runs the appropriate script to create a diary entry, and returns to Launch Center Pro. Counting the tap to start LCP itself, that’s two taps to make a diary entry, each on a large target with no chance for mistyping.

The scripts that do the work rely on the Dropbox module that comes with Pythonista. This module is not quite as easy to use as the one described in the Dropbox Python SDK documentation, and unfortunately the Pythonista documentation for the module contains some mistakes, but with a little trial and error I was able to get a set of scripts that worked.

The first step was to go to Dropbox’s App Console and “create an app.” This generated an app key and app secret that I could use to give my scripts access to my Dropbox files. I did that using this script, which is a slight modification of the authorization script in the Pythonista Dropbox documentation:

 1:  from dropbox import client, rest, session
 2:  import clipboard
 4:  # Get your app key and secret from the Dropbox developer website
 5:  APP_KEY = 'aaaaaaaaaaaaaaa'
 6:  APP_SECRET = 'bbbbbbbbbbbbbb'
 8:  # ACCESS_TYPE should be 'dropbox' or 'app_folder' as configured for your app
 9:  ACCESS_TYPE = 'dropbox'
11:  sess = session.DropboxSession(APP_KEY, APP_SECRET, ACCESS_TYPE)
13:  request_token = sess.obtain_request_token()
15:  url = sess.build_authorize_url(request_token)
17:  # Make the user sign in and authorize this token
18:  clipboard.set(url)
19:  print "url:", url
20:  print "This URL is on the clipboard. Please visit the website and press the 'Allow' button, then hit 'Enter' here."
21:  raw_input()
24:  access_token = sess.obtain_access_token(request_token)
26:  print 'key:', access_token.key
27:  print 'secret:', access_token.secret
28:  print
29:  client = client.DropboxClient(sess)
30:  print "linked account:", client.account_info()

The APP_KEY and APP_SECRET in Lines 5 and 6 are the strings I got from the Dropbox App Console. Running this script within Pythonista puts a Dropbox authorization URL on the clipboard and then pauses at Line 21. At this point, I went to Safari, pasted the URL, and authorized my app in much the same way I authorized Tweetbot, Storify, Pinboard, and other apps. Returning to Pythonista and the paused script, I tapped the Return key to allow the script to finish. Lines 26 and 27 printed out the access key and secret that are needed in the next script. With that, this script has done its job and is no longer needed.

By the way, the description of obtain_access_token is one of the places where the Pythonista Dropbox module documentation is wrong. It says the return value is a tuple of the key and the secret when it’s actually a single object with key and secret attributes. That took some time to figure out.

To avoid repeating a big chunk of code eight times, I wrote a module,, with a function that can be called from all the other scripts:

 1:  import dropbox
 2:  from datetime import datetime
 4:  def add_entry(entry):
 5:    "Add a timestamped entry to today's diary file."
 7:    # Initialize Dropbox.
 8:    app_key = 'aaaaaaaaaaaaaaa'
 9:    app_secret = 'bbbbbbbbbbbbbbb'
10:    access_key = 'ccccccccccccccc'
11:    access_secret = 'ddddddddddddddd'
12:    sess = dropbox.session.DropboxSession(app_key, app_secret, 'dropbox')
13:    sess.set_token(access_key, access_secret)
14:    client = dropbox.client.DropboxClient(sess)
16:    # Dates, times, and files.
17:    folder = '/Elements/Diary/'
18:    current =
19:    filename = current.strftime(folder +'%Y-%m-%d.txt')
20:    timestamp = current.strftime('%H:%M')
21:    dfiles = [ f['path'] for f in client.metadata(folder, list=True)['contents'] ]
23:    # Get the contents of today's diary file if it exists.
24:    if filename in dfiles:
25:      f = client.get_file(filename)
26:      log =
27:      f.close()
28:    else:
29:      log = ''
31:    # Add a new entry and save. Creates a new file if it doesn't exist.
32:    log += '%s\n%s\n\n' % (timestamp, entry)
33:    client.put_file(filename, log, overwrite=True)
35:  if __name__ == '__main__':
36:    add_entry('hello')

The function defined in this module, add_entry, does exactly what you’d expect from its name. Its single argument, entry, is what comes after the timestamp in a diary entry.

Lines 8–13 use the keys and secrets generated earlier to gain access to my Dropbox files. Line 14 initializes a Dropbox client process that handles the reading and writing of the files.

Lines 17–20 define the name and location of the diary file and define the timestamp. You’ll notice that my Diary folder is a subdirectory of a folder named “Elements.” Old-timers might remember that when the Elements app was the hot iOS text editor, it forced you to put all your files into a namesake Dropbox folder. I’ve linked every iOS text editor since then—none of which have been so restrictive—to that same folder.

Line 21 gets the names of all the files in the Diary folder. Line 24 then checks to see if there’s a file in there for today. If there is, it reads all the text from that file and puts it in a variable called log. If there’s no preexisting file for today, log is initialized to the empty string.

Line 31 adds the timestamp and entry to the end of log, and Line 32 writes log out to today’s file. This creates the file if it doesn’t already exist and overwrites the existing file if it does.

With doing all the hard work, the individual scripts for each common entry are easy. Here’s the one named Leave

1:  import diary
2:  import sound
3:  import webbrowser
5:  diary.add_entry('Leaving home')
6:  sound.play_effect('Coin_2')

Line 5 writes the entry, Line 6 plays a sound so I know when it’s done, and Line 7 takes me back to Launch Center Pro. The other seven scripts are exactly the same except for the argument to add_entry.

Which leaves just the definitions for the LCP actions. Here’s one:

Leave Home LCP action

The URL is


I suppose I shouldn’t have left the space in the script name—that’s the reason for the %20. The .py extension isn’t needed in the URL because Pythonista knows to add it.

Apart from the quick, one-handed entry, the best thing about this solution is that it’ll be easy to extend if I start using other common entries in the future.

  1. I think Editorial would work, too, but I’m not as familiar with it. 

]]> 0
Back to LaunchBar Tue, 19 Aug 2014 01:50:50 +0000 I gave Alfred a fair shot, I think. A two- to three-week trial in which I used it exclusively on both of my Macs. I even created some workflows to run scripts that I used to run through LaunchBar. And I really wanted Alfred to “stick,” because it uses far less memory than LaunchBar. But I’m back running LaunchBar again.

Two things brought me back. First, I didn’t like how Alfred wanted me to start folder and file searches by hitting either the spacebar or the single quote key. There are ways to have Alfred search files and folders without using this signal, but the preference pane for changing the setting warns against it. I didn’t want to slow Alfred down.

Alfred defaults

Which leads to my second problem: Alfred was, on my iMac at least, distinctly slower than LaunchBar at finding files and folders. I didn’t notice a speed difference on my MacBook Air—probably because its “disk” is all flash storage and only 128 GB—but Alfred’s lag was palpable on the iMac. It drove me crazy.

So what about LaunchBar’s huge appetite for RAM? That was, after all, the reason I gave Alfred a try. I went through LaunchBar’s index settings and pared down both the number and depth of the folders it indexes. I still get the quick results I want—I’m not sure why some of the settings were the way I used to have them—and LaunchBar’s long-term memory footprint is now down to about 100 MB on the MacBook Air and about 150 MB on the iMac. To be sure, this is about an order of magnitude more than what Alfred uses, but it’s a far cry from the 500–900 MB that LaunchBar was using before. And it’s worth it to get the behavior I want.

]]> 0
TextExpander and Numbers Fri, 15 Aug 2014 05:07:46 +0000 When Apple revived the iWork apps after their four-year coma, users soon found that the newly awakened versions were diminished. Some of the features that were cut have been brought back, but the ability to define named constants in Numbers—which I used in my expense report template—has not reappeared. I’ve learned, though, that I can use TextExpander instead, and I now have a few simple snippets that are even easier to use than named constants.

I use the snippets to enter mileage expenses when I drive my car on business. The IRS rate changes from year to year—currently it’s 56¢ per mile—and I hate having to look it up. As I said, I used to have a constant, named miles, defined in my expense report template to equal the current rate. To enter the mileage expense for a 25-mile trip, for example, I’d type


into the cell and it would do the substitution and the calculation. Simple, but no longer possible. I suppose I could set up a cell in a hidden part of the expenses table and get the same effect, but I don’t like hidden cells. It’s too easy to make mistakes when you can’t see everything.

I set up an Expenses folder in TextExpander. The snippets within it expand after any character and work only in Numbers.

TextExpander Expenses folder

The fundamental snippet in the group is for the mileage rate. You might think I could just define it as 0.56, and that’s what I tried first, but I soon found that Numbers does some odd things with typed input. When I tested the snippet by typing


into a cell, I heard the TextExpander expansion sound, and the ;mi disappeared, but nothing was substituted in its place. After a bit of tinkering, I found that a snippet with the content =0.56* would always expand, so that’s what I used.

Mileage rate snippet

Now I type ;mi into a cell, it expands to =0.56*, and I type the number of miles as the second term of the multiplication instead of the first. It’s a little different from my old habit, but it was easy to get used to.

Trips to the airport are pretty common, so I defined two other snippets, one for the trip to Midway and another for the trip to O’Hare. They start by invoking the mileage rate snippet and then add the number of miles to the end. If the mileage rate changes next year, I only have to change one snippet.

Midway snippet

I have a tendency to think in terms of complicated AppleScript or shell script snippets, but it’s often the simplest snippets that are the most useful.

In fact, as I was typing this up, I realized that snippets for the tolls I pay on my way to and from the airports would be just as valuable. I’ll be making those as soon as this is published.

]]> 0
A brief construction bestiary Tue, 12 Aug 2014 05:59:04 +0000 This post was inspired first by Marco Arment and his son, Adam:

Fake Cheerios are better from a backhoe. @ Mont Olympos Restaurant
Marco Arment (@marcoarment) Aug 10 2014 9:18 AM

Click the Instagram link to see Adam using a clever spoon substitute. My predictable reaction:

@marcoarment I love the photos of your son and his toys but feel obligated to point out that that’s not a backhoe.
Dr. Drang (@drdrang) Aug 10 2014 11:51 AM

The post was further inspired by Daniel Jalkut, who, like all smart people, isn’t afraid to confess his ignorance on topics outside his comfort zone:

@marcoarment @drdrang Front end loader? Everything I know about trucks comes from those baby picture books.
Daniel Jalkut (@danielpunkass) Aug 10 2014 1:21 PM

What I know about construction equipment comes from growing up with a father who was a design engineer at Caterpillar for 30 years and from my own 20+ years investigating equipment failures. This, far more than the little amateur programming projects I usually write about here, is my comfort zone. So I decided to break out of my usual blogging habits and actually write about something I know.

This is also an exercise in nostalgia. The photo of Adam reminded me of my older son, Joe, who was thoroughly obsessed with construction equipment when he was that age. Nowadays, as a tall, deep-voiced high school senior, he wouldn’t know the difference between a loader and a backhoe, but when he was 3–4 years old, he was an absolute expert. The only thing he liked more that flipping through books with pictures of Big Muskie and the Silver Spade, was going with me to local construction sites and seeing machines at work.

The equipment names I’ll be giving here are what manufacturers use. Construction workers have any number of names for these machines—a small percentage of which don’t even involve profanity—and I’ll include as many of these nonstandard names as I can think of.


Cat D6T

Photo from Caterpillar.

Dozers are the ur-machine of earthmoving, and the segmented steel tracks they run on are what gave Caterpillar its name.1 Each individual segment is called a shoe, and the spines that stick out of the shoe and dig into the soil for traction are called grousers. The tracks are meant to handle rough terrain while also spreading the load of the machine over a large area of ground contact.

The single wide blade at the front is for grubbing, pushing, and smoothing. Hydraulic cylinders behind the blade adjust its elevation, tilt, and horizontal angle. Dozers are often fitted with a ripper tooth on the back for loosening hard soil and are also used to pull other equipment around on a job site.


Cat 966M wheel loader

Photo from Caterpillar.

Lots of machines are called loaders, but the most common is the wheel loader, shown above. It’s not called a wheel loader because it loads wheels, it’s called that because it has wheels. It really should be called a wheeled loader, but it’s too late to change now.

Loaders have a wide bucket on the front that can be used for shallow digging but is usually used to scoop up loose material and load it2 into trucks. The position of the bucket has led to these often being called front-end loaders, but the front-end part is redundant. I’ve never seen one with a bucket at the back end.3

Some loaders run on tracks instead of wheels. As you might guess, they’re called track loaders. When Joe was at the peak of his machinery love, he was with me once at a store, looking out the front window at some construction work going on across the street. Another little guy, about a year older, was watching too, and said he liked the bulldozer. “That’s not a bulldozer,” said Joe. “That’s a track loader.” I was never prouder.

The very small loaders you see used by landscapers are officially known as skid steer loaders but are usually called Bobcats for the same reason facial tissues are usually called Kleenex.

Update 8/13/14
Reader Jonas Nilsson sent me a link to this image of a Volvo tractor with a loader attachment at its back end. According to Jonas, the name of this equipment in Swedish translates to back loader or back-end loader. You’ll note that in the linked photo the attachment is equipped with forks, not a bucket, but the mechanism could certainly accomodate a bucket.

Back loader attachment

Photo from Wikimedia.

Jonas says these back loaders used to be popular in northern Europe because they were cheap, but their disadvantages eventually outweighed the cost savings and they’re fairly rare now. I’ve seen plenty of farm tractors in the US with loader attachments on the front, but never anything like this. Thanks, Jonas!


Cat 324E excavator

Photo from Caterpillar.

Excavators are for serious digging. They have a long, deep reach, and can switch buckets quickly for different types of digging operations. You’ll often see them outfitted with slings and cables to pick up pipe sections and lower them down into the trenches they just dug.

Many people refer to excavators as backhoes, but this isn’t quite right because the bucket is on the front of the machine, not the back. I’ve also heard them called trackhoes, which makes sense because they’re hoes on tracks,4 but very few people use that name and no manufacturer does.

By the way, there are two fundamentally different types of digging machines, and they get their names from the hand implements they mimic. Shovels dig by scooping down and away, hoes dig by drawing down and back. Hoes are more common, but you probably remember a famous shovel.

Mike Mulligan

Photo from Amazon.

Here’s a little more excavator nomenclature. The two parts of the arm are called the boom and the stick. The boom is the piece closest to the machine; the stick is the piece between the boom and the bucket. The boom, the stick, and the bucket are operated independently.

Backhoe loader

Cat 420F backhoe loader

Photo from Caterpillar.

The backhoe loader (often called the loader backhoe) is a hybrid machine with a loader bucket on the front and an excavator attachment on the back. For this machine, the word backhoe makes sense because the hoe is on the back. The operator, who normally faces forward toward the loader bucket, swings the seat around when it’s time to use the backhoe. The legs off the rear are called outriggers, and they’re brought down to stabilize the machine when digging with the backhoe.

On some machines, the backhoe is truly a separate attachment to a tractor. On this type of equipment, the backhoe has its own little seat.

Bradco backhoe

Photo from Gearmore.


Cat 621K scraper

Photo from Caterpillar.

Scrapers are like dozers in that they have a blade that can cut through soil and level the ground. But a scraper doesn’t look anything like a dozer because its blade is at the bottom of a bowl—that’s the low part at the rear—which fills with the soil the blade cuts. A scraper can also be used “in reverse,” dumping soil out of the bowl and leveling it as it’s driven around the site.

I once had a project in Virginia in which the client kept referring to pans being used on his jobsite. It took me a while to realize he was talking about scrapers, substituting pan for bowl and then using that word for the entire machine. Even my dad hadn’t heard that one before.

Soil compactor

Cat 815F soil compactor

Photo from Caterpillar.

Soil compactors are often equipped with dozer blades to push soil around, but their shaped steel wheels are intended to do almost the exact opposite of a dozer’s tracks. The wheels focus the weight of the compactor onto a very small area to make the underlying soil more dense. The denser the soil, the better it is as a base for a roadway, parking lot, or floor slab.

I said brief

Because this is a blog post, and not a Dorling Kindersley book, I’m going to stop here, even though I haven’t even finished with earthmoving equipment. This makes for a good start, though, and should allow you to identify most of the machinery you see despoiling that nice wooded area to put in a strip mall.

  1. There are dozers with wheels, but they’re rare. Dozers are commonly used in areas that need to be smoothed out before wheeled vehicles can enter and work.

    Fun trivia: Caterpillar’s in-house newsletter was, and maybe still is, entitled Tracks and Treads

  2. Hence the name. 

  3. Now I have. See update below. 

  4. There are wheeled excavators, but they’re rare. 

]]> 0
Afghanistan, July 2014 Wed, 06 Aug 2014 00:28:11 +0000 Afghanistan made the news today, mainly because Major General Harold Greene was killed in an “insider attack” at a training base for Afghan soldiers. General Greene isn’t in this graph, but he’ll appear in the next one, joining nearly 3500 others.

Afghanistan, July 2014

]]> 0
Modular URL shortening TextExpander snippets Tue, 05 Aug 2014 05:03:49 +0000 Yesterday, John Flavin pointed out that my TextExpander snippets for getting Google-shortened URLs could be built better:

@drdrang Why repeat the ;furl code here? Why not just use %snippet:;furl% and make the whole thing a TE shell script?
John Flavin (@JFlavin) Aug 3 2014 11:11 AM

He’s right. Although I was thinking my snippets had to be self contained, they can call other snippets and incorporate the results—even if the snippet that’s doing the calling is a shell script or AppleScript snippet. TextExpander does the expansion first and then runs the script. So I refactored my snippets this way:

First, there’s my old snippet for getting the (unshortened) URL of the active browser tab, ;furl. It’s an AppleScript snippet with the following content:

 1:  tell application "System Events"
 2:    set numSafari to count (every process whose name is "Safari")
 3:    set numChrome to count (every process whose name is "Google Chrome")
 4:  end tell
 6:  if numSafari > 0 then
 7:    tell application "Safari" to get URL of front document
 8:  else
 9:    if numChrome > 0 then
10:      tell application "Google Chrome" to get URL of active tab of front window
11:    end if
12:  end if

(Note that I’m now using Vítor Galvão’s one-liner for Chrome.)

Next, I have a Python script, gshorten, that’s structured like the Pythonista script I use for shortening URLs on iOS, except that it takes the original URL from the command line and returns the shortened URL to standard output. It’s saved in my ~/Dropbox/bin folder. Here it is:

 1:  #!/usr/bin/python
 3:  import requests
 4:  import json
 5:  import sys
 7:  # Build the request.
 8:  shortener = ""
 9:  longURL = sys.argv[1]
10:  headers = {'content-type': 'application/json'}
11:  payload = {'longUrl': longURL}
13:  # Get the shortened URL and print it.
14:  r =, headers=headers, data=json.dumps(payload))
15:  sys.stdout.write(r.json()['id'])

The snippet I use to shorten the URL of the front browser tab uses both of these. It’s a shell script snippet with abbreviation ;surl and this content:

~/Dropbox/bin/gshorten '%snippet:;furl%'

It runs the ;furl snippet and uses the result as the argument to gshorten. What’s nice about this solution is that it’s using AppleScript for what it’s good for (communicating with applications) and Python for what it’s good for (everything else).

Finally, the snippet I use to shorten a URL on the clipboard has the abbreviation ;scurl and this content:

~/Dropbox/bin/gshorten '%clipboard'

It’s basically the same as ;surl except that it uses the clipboard as the argument to gshorten.

Splitting things up this way makes my system a bit more complicated, but there’s less repetition and, more important, each component does one thing. If I need to change the code for getting the front tab’s URL (to add another browser, for example, or if a browser changes its AppleScript library), I only have to change the code in ;furl. Similarly, if Google changes its API, I only have to fix the code in gshorten.

Someone my age should know enough to use modular design in the first place. Thanks to John for straightening me out.

]]> 0
Automatic shortened URLs via Google Sat, 02 Aug 2014 22:47:42 +0000 Back in the old days (that is, maybe three years ago), everyone on Twitter used some specialized URL shortening service, like or, to keep their tweets under 140 characters.1 That became counterproductive when Twitter started its own shortening service and built an infrastructure around it. Nowadays, it’s much better for your readers if you just paste in the full, true URL of the page you want to link to and let Twitter handle the shortening and the display.


Except when you want to include a link in a direct message. Twitter refuses most links in DMs because

  1. it doesn’t want to pass along spam or phishing attacks in DMs; but
  2. it doesn’t want to take responsibility for vetting the links before shortening them.

If you try to send a link via DM in the web interface, it responds with a terse “Your message can’t be sent.” In Tweetbot, you get a longer but no more satisfying explanation.

Tweetbot DM error

By “later,” I guess they mean “when Twitter changes its policy.”

Some links are allowed in direct messages. I don’t know all the possibilities, but I know you can include those from Google’s service. I don’t send a lot of direct messages, and those I send generally don’t include links, but when I need to send links, is what I use.

Yesterday I decided to automate the process of getting links by using Google’s URL Shortener API. I signed up for an API key, but after some experimentation, I found that the key wasn’t necessary. Maybe you need it if you want to track links, but I have no interest in that, especially for one-off links in direct messages.

I followed Google’s examples to learn how to shorten a URL from the command line using curl. Here’s a long example, split up over three lines:

curl \
 -H 'Content-Type: application/json' \
 -d '{"longUrl": ""}'

The -d argument is what’s POSTed, and as you can see, it’s in JSON format. The result is in JSON format, too:

 "kind": "urlshortener#url",
 "id": "",
 "longUrl": ""

What I wanted to make was a TextExpander snippet that would take the URL of the frontmost browser tab and return a shortened version of it. Here it is.

TextExpander URL shortener

It’s an AppleScript snippet with an abbreviation of ;surl.2 The AppleScript content is this script:

 1:  tell application "System Events"
 2:    set numSafari to count (every process whose name is "Safari")
 3:    set numChrome to count (every process whose name is "Google Chrome")
 4:  end tell
 5:  set longURL to "none"
 7:  if numSafari > 0 then
 8:    tell application "Safari" to set longURL to URL of front document
 9:  else
10:    if numChrome > 0 then
11:      tell application "Google Chrome" to set longURL to URL of active tab of front window
12:    end if
13:  end if
15:  set payload to "{\"longUrl\": \"" & longURL & "\"}"
17:  set cmd to "curl -s -H 'Content-Type: application/json' -d '" & payload & "' | awk '/^ \"id\":/ {gsub(/\"|,/, \"\", $2); print $2}'"
19:  return do shell script cmd

Lines 1–13 are essentially the same as my ;furl snippet. They get the URL of the active browser tab, from Chrome if it’s running or from Safari if it’s running. Line 15 then constructs the JSON payload, and Line 17 builds a call to curl just like the example above. It also pipes the JSON output to an awk one-liner to extract just the shortened URL. There’s a lot of backslash escaping of double quotation marks because AppleScript. Line 19 runs the command and returns the result.

(I decided to use awk here because the JSON returned by the API is pretty simple. If I were dealing with more complex output, I’d mimic what Greg Scown of Smile did in this blog post. He used a headless application called JSON Helper [free on the Mac App Store] to parse the longer JSON data returned from a currency conversion API call.)

I also made a similar snippet for shortening a URL on the clipboard. Its abbreviation is ;scurl and its AppleScript content is this script:

1:  set longURL to the clipboard
3:  set payload to "{\"longUrl\": \"" & longURL & "\"}"
5:  set cmd to "curl -s -H 'Content-Type: application/json' -d '" & payload & "' | awk '/^ \"id\":/ {gsub(/\"|,/, \"\", $2); print $2}'"
7:  return do shell script cmd

That takes care of OS X, how about iOS? There’s no AppleScript on iOS, and TextExpander doesn’t run scripts, so I went with a Pythonista script that replaces a URL on the clipboard with a shortened version. Here’s the script:

 1:  import requests
 2:  import json
 3:  import clipboard
 5:  # Build the request.
 6:  shortener = ""
 7:  longURL = clipboard.get()
 8:  headers = {'content-type': 'application/json'}
 9:  payload = {'longUrl': longURL}
11:  # Get the shortened URL and put it on the clipboard.
12:  r =, headers=headers, data=json.dumps(payload))
13:  clipboard.set(r.json()['id'])

On iOS, I copy the URL I want to shorten, switch to Pythonista, run the script, then switch to Tweetbot to paste the shortened URL into a DM. There’s probably a way to cut out a step or two by using an x-callback URL, but I haven’t messed around with that yet.

None of these scripts are forgiving. Inputs that aren’t URLs will produce nasty output that isn’t handled gracefully. Be aware of this if you want to adapt these scripts for your own use.

Update 8/5/14
I rewrote these scripts to make them easier to maintain.

  1. Ironically, the granddaddy of URL shorteners,, was too long for use on Twitter. 

  2. Following the principle of conservation of abbreviations, this is the same abbreviation I used to use for my old URL shortening snippet. No sense wasting strings. 

]]> 0
Alfred Fri, 01 Aug 2014 04:34:13 +0000 I’m giving Alfred a try. I’ve been using LaunchBar for 6½ years (ever since Alcor warned us that Quicksilver wouldn’t be stabilizing any time soon) and have ignored the many Alfred recommendations I’ve seen. LaunchBar was fast and reliable, and my fingers were trained to its rhythms. I even gave up on Jumpcut a couple of months ago to use LaunchBar’s clipboard history.

So why the change? Well, I’m not certain that I am changing. I’m going to be running Alfred exclusively for a couple of weeks, but that doesn’t mean I won’t be going back to LaunchBar. But what inspired me to start this trial is the prospect of running Yosemite on the machine I’m typing this on: a 2010 MacBook Air with a Core 2 Duo processor and 4 GB of RAM.

By all accounts, Yosemite will run on this computer, but my dismal experience running Lion on a 2006 iMac has made me leery of Apple’s assurances.1 A few days ago, I started wondering about the memory footprint of the apps I commonly run, so I opened up Activity Monitor and had a look. It showed LaunchBar using over 900 MB.

This was on a system that hadn’t been rebooted in ages, so the LaunchBar process was quite old. I quit and restarted LaunchBar to see if the 900 MB figure was an anomaly. LaunchBar’s footprint started out at about 100 MB but quickly climbed to over 400 MB. This was when I decided a look at Alfred would be prudent. I downloaded the basic (free) version and started it up. Much different.

Unless Activity Monitor is lying to me, LaunchBar regularly uses over 400 MB of memory and Alfred (sans Powerpack) uses around 25 MB.
Dr. Drang (@drdrang) Jul 29 2014 4:43 PM

Replies to this tweet told me that I could expect similar memory use by Alfred even with the Powerpack. That’s when I decided to buy the Powerpack and give it serious trial.

(To be fair to LaunchBar, I must mention that I was able to reduce its memory use by tweaking some of its indexing settings. But it was still using over 100 MB, which seems like too much for an app that’s always running in the background.)

Alfred is, for the most part, enough like LaunchBar that my fingers do the right thing, but there are some exceptions. My thumb keeps hitting the spacebar to drill down through folders but all that does in Alfred is add a space to the search string. I have to retrain myself to use the arrow keys. Conversely, instead of thumbing the spacebar to start a file search, I tend to start typing the name of the file right away, which usually causes Alfred to start a Google search.

Also, Alfred hasn’t been able to find some of the AppleScripts I used to run from LaunchBar, so I’ve started turning them into Workflows. These Workflows are embarrassingly simple—just a keyword and an AppleScript—but they work and take almost no time to make.

Alfred Expense template workflow

I start by clicking the + button at the bottom of the window and work my way through the nested menus until I find the Keyword to AppleScript item.

Alfred AppleScript template

Then its just a matter of filling the keyword and title into the Keyword panel and pasting my previously written AppleScript between the on alfred_script(q) and end alfred_script lines in the AppleScript panel. For the Expenses template workflow shown above, I used the script described in this post from a couple of months ago. The full script in Alfred is

 1:  on alfred_script(q)
 2:    set today to current date
 3:    tell application "Numbers"
 4:      activate
 5:      make new document with properties {document template:template "Expenses"}
 6:      -- delay 2 -- might need to wait for Numbers to launch
 7:      tell document 1
 8:        tell sheet 1
 9:          tell table 1 to set value of cell 1 of column 2 to today
10:          tell table 2 to set selection range to range "A2:A2"
11:        end tell
12:      end tell
13:      activate
14:    end tell
15:  end alfred_script

One place where Alfred is clearly better than LaunchBar is in its clipboard history. Alfred shows several lines of each clipboard entry in its right panel, whereas LaunchBar shows only the beginning of the first line, much like Alfred’s left panel.

Alfred clipboard history

So far, the frustrations I’ve felt with Alfred have been fixed by tweaking its settings. If that remains the case, I’ll probably switch to it permanently. To get essentially the same functionality using much less memory is too good a deal to pass up.

  1. John Gruber wrote a post many years ago about how all the OS X updates (to that point) actually made his old hardware run better because the newer versions had more efficient code. That was my experience, too, until Lion. It ran fine on my MacBook Air, but the constant memory swapping caused no end of disk thrashing on my iMac. To be sure, that iMac was light on RAM—it had only 3 GB, but in my defense, that was the maximum it could address—but it was supposed to work with Lion. That was the first time Apple misled me, and I haven’t trusted them on system requirements since then. 

]]> 0
Documentation Wed, 30 Jul 2014 03:54:30 +0000 Since Marco Arment tweeted a link to my post on Overcast, I’ve gotten about twice as much traffic as usual and an undeserved reputation as an expert on Overcast’s features. Because of the latter, I’ve been fielding questions about Overcast that should be going to Marco himself, the wily bastard.

Much as I enjoy acting as Marco’s unpaid support tech, I really wish had a couple of pages of explanation for its settings and use. Overcast is easy to use, but not every feature is obvious.1 This is not a bad thing. Even behavior that seems obvious in retrospect will not necessarily be obvious upon first use. When using a new app, users always bring with them expectations and habits from the apps they used before. A new app that doesn’t have features that are at least a little unfamiliar, that does nothing other apps don’t already do, has no reason for being.

Overcast is hardly the only app that could use a little documentation. There seems to be belief among software developers nowadays that providing instructions indicates a failure of design. It isn’t. Providing instructions is a recognition that your users have different backgrounds and different ways of thinking. A feature that’s immediately obvious to User A may be puzzling to User B, and not because User B is an idiot.

You may not believe this, but when the Macintosh first came out everything about the user interface had to be explained. How to click a button, how to select an item from a menu, how to drag an item from one place to another. Oh, it was way easier to use a Mac than any other computer, but the conventions we now take for granted weren’t conventions yet because no one had experience with mice, menus, windows, and icons. All of these features seem intuitive to today’s users because they learned them as children and don’t remember not knowing them.

Jef Raskin wrote about this long ago in a paper with the wonderfully summarizing title “Intuitive Equals Familiar.” Here’s Raskin saying it better than I have:

As an interface designer I am often asked to design a “better” interface to some product. Usually one can be designed such that, in terms of learning time, eventual speed of operation (productivity), decreased error rates, and ease of implementation it is superior to competing or the client’s own products. Even where my proposals are seen as significant improvements, they are often rejected nonetheless on the grounds that they are not intuitive. It is a classic “catch 22.” The client wants something that is significantly superior to the competition. But if superior, it cannot be the same, so it must be different (typically the greater the improvement, the greater the difference). Therefore it cannot be intuitive, that is, familiar. [emphasis mine]

Let’s think about it another way. Here’s the layout of cab controls in a Caterpillar D5 dozer. Every D5 comes with an operator’s manual, and no one would expect otherwise, even though Caterpillar’s designers do their best to make the controls discoverable, comfortable, and easy to use; even though equipment operators are expected to be trained; and even though there are conventions for control design among construction equipment manufacturers.

Cat D5 cab

A typical Mac app has more controls—buttons, sliders, menu items, whatever—than the cab of a D5. Anyone can buy an app and start using it with no training whatsoever. And yet somehow it shouldn’t have an operator’s manual?

The desire to make computer programs as easy to use as possible is admirable, and the success developers have had in doing so benefits us all. But a little instruction here and there wouldn’t hurt.

  1. John Siracusa’s comments about Overcast’s settings on the latest ATP episode match up with my experience. 

]]> 0
Hodgepodge Tue, 29 Jul 2014 05:26:25 +0000 A little followup on recent posts:

Path Finder trial

After what I thought was a fair trial of Path Finder, I’m back using to using the regular ol’ Finder again. I didn’t run across anything especially bad about Path Finder, but I didn’t run across anything compelling, either.

About a week ago, after a couple of weeks of constant use, I turned off Path Finder. My thinking was that if I missed it, it’d be worth returning to. I haven’t even thought about it until today—a strong sign that it just isn’t for me.

I know there are lots of smart people who swear by Path Finder, but this is the fourth or fifth time I’ve given it a trial run, and it’s never stuck with me. I won’t be trying it again.

Quicker Markdown linking with TextExpander

I got lots of comments on this post, most of which were suggestions for improvements. I feel guilty about the time people put into their responses, because I don’t use TextExpander to make Markdown links—the post was just a demonstration of how a little AppleScript can make your snippets more efficient.

I don’t use TextExpander for Markdown links because it’s best suited for inline links and I prefer reference links. The cursor movement and reference counting necessary for efficient reference linking is something that TextExpander just isn’t equipped to do because it can’t read the document I’m working on. Reference links require a system more integrated with your text editor, so I use a set of scripts in a BBEdit package. The reference link scripts are explained in this post.

The best thing to came out of that post was a link from Vítor Galvão to this wonderful set of AppleScript excerpts for getting the URL and title of the active browser tab for Safari, Chrome, Chrome Canary, Chromium, and WebKit. Turns out™ I could’ve been using a one-liner for the Chrome portion of my ;furl snippet.

Better Markdown folding in BBEdit

I’ve been writing long reports for work recently, and this script for intelligent folding of Markdown sections in BBEdit has been a big help in keeping the reports organized and keeping me focused on whatever section I’m writing.

I’d still prefer it if Rich Siegel recognized this as the right way to fold Markdown and incorporated it into BBEdit proper, but until that time I’ll get by with my script.

]]> 0