Archive for the ‘productivity’ Category
Why vi?
July 3rd, 2008
You may have seen in the past week or so links to Beeswax, a new terminal-based productivity application inspired by Lotus Agenda. I’m not looking for a new productivity app—OmniFocus is working pretty well for me now—but I did find it interesting that Beeswax uses vi keybindings for adding and editing tasks.
Vi may be the oldest text editor still in wide use. The original vi was written by Bill Joy while he was a member of the BSD development group in the ’70s. It’s been rewritten several times since then; the most popular version nowadays is probably vim.
Text editing in vi is characterized by modes. Text is added to a file while in insert mode, where every keystroke results in a character appearing on the screen, just like the most familiar editors of today. Text is edited in command mode, where keystrokes do things to the text in the file. For example:
- x deletes the character at the cursor;
- 5x deletes five characters, starting at the cursor;
- w moves the cursor forward one word;
- d3w deletes three words, starting at the cursor.
As you can see, vi commands can be combined and multiplied. Also, the command mode eliminates the need for Command- and Control-key combinations.
Modal editing may seem weird now, but it was the norm in the old days. In fact, vi was a big hit because it was a “screen editor,” allowing you to look at and work on an entire screenful of text at a time. Most editors back then were “line editors,” which restricted you to just one line at a time.
Vi is intriguing to productivity geeks because its ability to combine commands gives users the leverage to do a lot of editing with very little typing. Merlin Mann at 43 Folders has mentioned vi several times, both on the blog and on the MacBreak Weekly podcast. I’ve gone through my vi phases, too.
Back in my Linux days, I would periodically use vi as my primary text editor for a week or two at a time, but the modes always defeated me. I can’t tell you how many times I had to delete “:w” from my work1. I’m glad I spent the time to learn the basics, because vi can be very useful when I need to ssh into a remote computer and do a quick file edit. If the remote computer is Unix-like, some form of vi will certainly be there. But I was never able stay with vi as my regular text editor because of how I write.
As I see it, there are three types of writer:
First, there’s the kind that write final copy directly. Words, sentences, and paragraphs flow out in a smooth stream with no need for editing. While I don’t think any professional writing gets done this way, I know many people who can do correspondence like this. I’ve often gotten mail from clients with the notation at the bottom that the letter was “dictated but not reviewed.” Since these people don’t edit, the text editor they use is immaterial.
Second, there’s the kind that write in drafts. When I was a kid in the pre-PC era, school essays were always written as a longhand draft first, then edited and typed up as a final copy. Even today, when everyone writes on a computer, many writing guides suggest that you “get everything out” in a first draft and then clean things up with a good editing session. Vi’s modal editing can be great for this kind of writer. All of the first draft is done in insert mode and all the later editing in command mode.
Finally, there’s the kind that constantly fiddles with the text. This is me, and this is why my experiments with vi failed. I tend to rewrite sentences as I’m typing, stopping in the middle to go back and reset the tense or flip clauses around. It’s rare that I can type an entire paragraph without stopping to edit it. The need to keep shifting in vi from command to insert mode makes it a very clumsy editor for this type of writer.
I’ve tried to change my writing habits. I’ve tried to turn my brain’s internal editor off and just let the words come out, trusting myself to fix them later on. It would make writing much easier, regardless of the text editor I use. But I can’t do it.
One of the few advantages of reaching middle age is coming to recognize your strengths and weaknesses and knowing what you can change and what you can’t. This is something I can’t.
I wish the Beeswax developers well; I’m sure their system will be just the thing for many people. But I know my limitations.
-
That’s the command for saving. ↩
Repeating dates in OmniFocus and iCal
June 30th, 2008
In trying to create a repeating OmniFocus task, I learned that its handling of repeating dates is pretty rudimentary. iCal is much better, but is still lacking some niceties that can come in handy.
My company uses an outside bookkeeper who comes to our office on the last Friday of every month to do the accounting that pays our bills, taxes, and salaries. Some paperwork needs to be done by one of the partners before her visit, and if I’m in town, I’m usually the one who does it. Last week I tried to set up an OmniFocus task to remind me of the necessary paperwork, but I was stopped short by some of OmniFocus’s limitations.
I started with what I thought was the obvious approach. I created an Accounting project and added a repeating task to get the needed paperwork ready. Two problems:
- When I’m showing Next Actions—which is my usual working Perspective—all the Next Actions appear. But the paperwork for the bookkeeper shouldn’t be done until a few days before salary checks are cut, so this task will just clutter up my view for most of the month. I may be able to get around this problem by fiddling with start dates or by scheduling an AppleScript to toggle the task status from On Hold to Active near the end of the month.
- OmniFocus’s Repeat Every setting is just too limited. It allows you repeat a task every so many days, weeks, months, or years, but it can’t handle something like “the last Friday of the month.”

This second problem is the killer, and it’s a pretty embarrassing lack of functionality. The algorithms for this kind of repetition are well established and available. Papers and books on the topic by Reingold and Dershowitz can be found here, and you can always look at the source code for the Calendar/Diary module in Emacs, or for the old BSD calendar program, which comes with OS X.
iCal has a much better repeating date implementation. I’ve used it to create an event for the bookkeeper’s visit on the morning of the last Friday of every month.

This is great for keeping track of the visits, but isn’t ideal for keeping track of my paperwork task. David Allen saith that the calendar is only for things that must be done on that day. The paperwork can be done any time in the week before the last Friday of the month and is best done a day or two before the bookkeeper’s visit.1 Since OmniFocus can’t do what I need on its own, the iCal entry will have to suffice until the OmniGroup improves its date repetition code, or until I can figure out a way to force OmniFocus to do my bidding.
I should mention here that iCal’s repeated date handling isn’t perfect. It can’t, for example, handle US election days or the US federal holiday for Christmas. Election day is not the first Tuesday in November, it’s the day after the first Monday in November. And the federal Christmas holiday—the day you get off work—is December 25 only if December 25 falls on a weekday. If it falls on a weekend, the Christmas holiday is the weekday nearest to December 25. Try doing either of these as a repeating event in iCal.
Although I have no solution now, I’m not giving up. Maybe I can use iCal’s ability to schedule AppleScripts to run a few days before an event to create an OmniFocus task telling me to get the paperwork ready. I need to dig into OmniFocus’s AppleScript library.
OmniFocus and OmniOutliner Pro
June 27th, 2008
My free test period for OmniFocus ran out today and I couldn’t open my GTD lists. This bothered me, which I took to be a sign that it’s a program I really use and should buy.
OmniFocus normally sells for $80, but if you’re a licensed owner of OmniOutliner Pro, you can buy OmniFocus for $60. I don’t own OO Pro, but I do have the regular version of OO that was bundled with my iMac. Since that can be upgraded to OO Pro for $30, doing the upgrade and then buying OmniFocus was just $10 more than getting OmniFocus alone. OK, OmniGroup, you win—I’ll get both.
And yes, I’ll get OmniFocus for the iPhone when it comes out. I’m turning into the OmniBitch.
My no-server personal wiki—Part 3
June 26th, 2008
This the last post describing the self-contained wiki-like system I use to keep track of project notes at work. The first post in the series explained my motivation for creating this system. The second post described how I use it. In this post, I’ll show the behind-the-scenes programming that puts it together.
Makefile
Let’s start with the Makefile. I mentioned before that the HTML pages are generated by running the make utility in the notes directory. Here’s the Makefile.
1: # Makefile for project notes.
2:
3: mdfiles := $(wildcard *.md)
4: htmlfiles := $(patsubst %.md, %.html, $(mdfiles))
5:
6: all: notesList.js $(htmlfiles)
7:
8: notesList.js::
9: python buildNotesList.py > notesList.js
10:
11: %.html: %.md project.info header.tmpl footer.tmpl
12: python buildPage.py $* > $@
13:
14: clean:
15: rm $(htmlfiles) notesList.js
Lines 2 and 3 use wildcards and pattern substitutions to create variables that define all the Markdown-formatted (.md) content files and the corresponding HTML pages.
Line 6 defines the all rule; because it’s the first rule in the Makefile, it’s also the default rule, so executing make is the same as running make all. It builds the JavaScript file notesList.js and the HTML pages.
Lines 8 and 9 define the rules for building the notesList.js file. It’s built by running the Python program buildNotesList.py, which we’ll get to in a bit. As we’ll see, notesList.js defines the sidebar links to all the HTML pages in the notes folder. Since new notes can be added at any time, notesList.js must be rebuilt whenever make is run.
Lines 11 and 12 define the rule for building the HTML notes pages. A page gets (re)built whenever
- its corresponding
.mdfile is created; - its corresponding
.mdfile is updated; or - whenever the header or footer template file is updated.
The page is built by running another Python program, buildPage.py, taking the corresponding .md file as input.
Lines 14 and 15 define a cleanup rule that deletes the HTML files and notesList.js. This rule is executed by running make clean from the Terminal. It’s sort of a defensive rule; if things get really screwed up, make clean will take me back to a pristine state. All the deleted files can be regenerated by running make.
notesList.js and buildNotesList.py
As mentioned above, notesList.js is a JavaScript file that’s used to generate the list of links to other notes pages that appears at the top of the sidebar (see the screenshot of a page in Part 2). It defines a JavaScript function, showNotesList, that writes a series of list items with links to the notes pages. In the skeleton version of the notes folder described in Part 2, there is only one HTML notes page so notesList.js is very simple:
function showNotesList(){
document.write('<li><a href="aa-overview.html">Overview</a></li>')
}
The notesList.js file is generated by the Python program, ‘buildNotesList.py`:
1: #!/usr/bin/python
2:
3: import os
4:
5: # Get the titles of all the notes files in the directory. The
6: # title is assumed to be the first line of the file. Truncate
7: # the title at a word boundary if it's longer than maxlength.
8: # Print out a JavaScript function that will write an HTML list
9: # of the notes files.
10:
11: fileLI = []
12: maxlength = 35
13: allFiles = os.listdir('.')
14: baseNames = [ f[:-3] for f in allFiles if f[-3:] == '.md' ]
15: for fn in baseNames:
16: f = file(fn + '.md')
17: top = f.readline()
18: title = top.strip('# \n')
19: if len(title) > maxlength:
20: words = title.split()
21: twords = []
22: count = 0
23: for w in words:
24: if count + len(w) > maxlength:
25: break
26: else:
27: twords.append(w)
28: count += len(w) + 1
29: title = ' '.join(twords) + "…"
30: fileLI.append('<li><a href="%s.html">%s</a></li>' % (fn,title))
31: f.close()
32:
33: print '''function showNotesList(){
34: document.write('%s')
35: }''' % ' '.join(fileLI)
I think the comment at the top of the file describes it pretty well. The trickiest part of the program is getting the title of the link. The title of the page is the first line of the .md file, with any leading or trailing hash marks (#) deleted. But since a page title could be pretty long and the sidebar is rather narrow, I wanted the link titles to be truncated to the nearest word boundary short of 35 characters. That’s what Lines 19-29 do, putting an ellipsis (…, HTML entity …) at the end to indicate the truncation.
buildPage.py
This is the real workhorse of the system.
1: #!/usr/bin/env python
2:
3: import sys
4: import os
5: import os.path
6: import time
7: import string
8: import urllib
9:
10: # The argument is the basename of the Markdown source file.
11: mdFile = sys.argv[1] + '.md'
12:
13: # Open the page files and process the content.
14: header = open('header.tmpl', 'r')
15: footer = open('footer.tmpl', 'r')
16: cmd = 'MultiMarkdown %s | SmartyPants' % mdFile
17: content = os.popen(cmd, 'r')
18:
19: # Make the template.
20: templateParts = [header.read(), content.read(), footer.read()]
21: template = string.Template(''.join(templateParts))
22:
23: # Close the page files.
24: header.close()
25: footer.close()
26: content.close()
27:
28: # Initialize the dictionary of dynamic information.
29: info = {}
30:
31: # Dictionary entry with long modification date of the Markdown file.
32: mdModTime = time.localtime(os.path.getmtime(mdFile))
33: info['modldate'] = time.strftime('%B %e, %Y', mdModTime)
34: info['modldate'] = info['modldate'].replace(' ', ' ')
35:
36: # Dictionary entry with short modification date of the Markdown file.
37: info['modsdate'] = time.strftime('%m/%e/%y', mdModTime)
38: info['modsdate'] = info['modsdate'].replace(' ', '')
39:
40: # Dictionary entry with modification time of the Markdown file.
41: info['modtime'] = time.strftime('%l:%M %p', mdModTime)
42: if info['modtime'][0] == ' ':
43: info['modtime'] = info['modtime'][1:]
44:
45: # Dictionary entry with absolute path to the Markdown file (for editing).
46: info['mdpath'] = os.path.abspath(mdFile)
47:
48: # Add project info to the dictionary.
49: projInfo = open('project.info', 'r')
50: for line in projInfo:
51: if line[0] == '#' or line.strip() == '':
52: continue
53: name, value = [s.strip() for s in line.split('=', 1)]
54: if name in info:
55: info[name] += '\n' + value
56: else:
57: info[name] = value
58:
59: projInfo.close()
60:
61: # Dictionary entry with absolute path to project info file (for editing).
62: info['infopath'] = os.path.abspath('project.info')
63:
64: # Convert the contacts into a series of HTML list items.
65: if 'contact' in info:
66: contactLI = []
67: cl = [s.split(':',1) for s in info['contact'].split('\n')]
68: for c in cl:
69: if len(c) == 1:
70: contactLI.append('<li>%s</li>' % c[0])
71: else:
72: contactLI.append('<li><a href="addressbook://%s">%s</a></li>'\
73: % tuple(reversed(c)))
74: info['contactlist'] = '\n'.join(contactLI)
75: else:
76: info['contactlist'] = ''
77:
78: # Output the template with the dynamic information substituted in.
79: print template.safe_substitute(info)
It does basically five things:
- It processes the given Markdown file through MultiMarkdown (Fletcher Penney’s extended version of Markdown that includes support for tables and other niceties) and SmartyPants (John Gruber’s typographical conversion program that substitutes curly quotes for straight quotes and m- and n- dashes for multiple hyphen sequences). See Lines 16 and 17.
- It concatenates the header template, the just-generated main content, and the footer template into a new string template that will later be turned into the HTML page file. See Lines 20 and 21.
- It queries the file system for info about the source Markdown (
.md) file and creates a set of dictionary entries with that information. See Lines 31-46. - It goes through the
project.infofile, and creates another set of dictionary entries with the data it reads from that file. See Lines 48-76. - It creates the HTML page by substituting the dictionary entries from Steps 3 and 4 into the string template from Step 2.
header.tmpl and footer.tmpl
The header template file looks like this:
1: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
2: "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3: <html>
4: <head>
5: <title>$projname ($projnumber)</title>
6: <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
7: <link rel="stylesheet" type="text/css" media="all" href="notes.css" />
8: <link rel="stylesheet" type="text/css" media="print" href="notes-print.css" />
9: <!-- <script type="text/javascript" src="file:///Users/drang/Library/JavaScript/jsMath/easy/load.js"></script> -->
10: <script type="text/javascript" src="styleLineNumbers.js"></script>
11: <script type="text/javascript" src="notesList.js"></script
12: </head>
13: <body onload="styleLN()">
14: <div id="container">
15: <div id="title">
16: <h1 class="left">$projname</h1>
17: <h1 class="right">$projnumber</h1>
18: </div> <!-- title -->
19: <div id="sidebar">
20: <h1>Project notes:</h1>
21: <ul>
22: <script type="text/javascript">showNotesList()</script>
23: </ul>
24: <hr />
25: <h1>Contacts:</h1>
26: <ul>
27: $contactlist
28: </ul>
29: <hr />
30: <h1>Source:</h1>
31: <ul>
32: <li><a href="txmt://open?url=file://$mdpath">Edit in TextMate</a></li>
33: <li>Last modified<br />
34: $modldate<br />
35: at $modtime</li>
36: </ul>
37: <hr />
38: <ul>
39: <li><a href="txmt://open?url=file://$infopath">Edit project info</a></li>
40: </ul>
41: </div> <!-- sidebar -->
42:
43: <div id="note">
Although it’s called header.tmpl, you’ll see that it really contains both the header and the sidebar.
Line 9 in the <head> section contains a call to a JavaScript file that isn’t in the notes folder. This is one of the files that comes with the jsMath library, a set of JavaScript and PNG files created by Davide Cervone that allow equations to be embedded in the pages without the need for MathML support. Since most people don’t need equations in their notes, I’ve commented this line out. My project notes often do need equations, so I usually have this line uncommented and it brings in jsMath library from its spot in my ~/Library/JavaScript folder.
The footer template looks like this:
1: <hr />
2: <p class="info">
3: Source: <a href="txmt://open?url=file://$mdpath">$mdpath</a><br />
4: Last modified: $modldate at $modtime<br />
5: <!-- This page built: $buildtime -->
6: </p>
7: </div> <!-- note -->
8: </div> <!-- container -->
9: </body>
10: </html>
It adds a little notation at the bottom of the page, telling where the source file is and when it was last updated.
The structure of the resulting HTML page is pretty simple:
<div id="container">
<div id="title">
blahblahblah
</div> <!-- title -->
<div id="sidebar">
blahblahblah
</div> <!-- sidebar -->
<div id="note">
blahblahblah
</div> <!-- note -->
</div> <!-- container -->
CSS
I’m not going to go through the CSS files because they’re long and not that interesting. suffice it to say that notes.css floats the sidebar to the right and defines a set of colors, type sizes, and spacing that I find pleasing. Not surprisingly, it’s quite similar to the layout of this blog. The CSS file for printing, notes-print.css, hides the sidebar because navigation links don’t work on paper and turns all the colors to black and white because that’s the kind of printer I use.
styleLineNumbers.js
If a notes file contains source code with line numbers, the JavaScript functions in this file will style it nicely and allow me to toggle the line numbers on and off. It’s the same set of functions I use on this blog and which I’ve described in an earlier post.
All together now
If you’re interested in playing around with this system, I’ve made a zip file of my skeleton notes folder available to download. Have fun, and let me know of any improvements you make.
My no-server personal wiki—Part 2
June 25th, 2008
In my last post, I gave my reasons for needing a wiki for project notes, what I wanted it to do, and why I decided to roll my own instead of going with any of the readily available free or commercial offerings. In this post, I’ll describe how my system works. If some of the choices I’ve made seem odd to you, the earlier post should explain the whys and wherefores.
The files for the wiki—both the content and the build files—sit in a folder called “notes.” This makes the system portable. I keep a skeleton version of this folder on my Desktop, and whenever I need a notes wiki for a new project, I drag a copy from the Desktop into the project folder. Here’s a view of the skeleton.

The content is kept in the Markdown-formatted files with an .md extension. The skeleton provides just one of these, aa-overview.md, which is filled with mostly nonsense. Any file added to the folder with an .md extension will be taken as the content for a new page. The wiki pages themselves are the .html files with the same basenames as the .md files. Everything else in the folder is either a programming, template, or configuration file.
The HTML version of aa-overview is intended to be the home page of the wiki. For the skeleton file, it looks like this:

The skeleton aa-overview.md, as with all the Markdown files, contains just the content of the main section of the page:
# Overview #
## Background ##
This is where I describe the project.
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
The header, the sidebar, and the footer are all built from the template and configuration files. The page is built statically, so aa-overview.html is a full HTML file, not a fragment.
The top section of the sidebar contains links to all the notes files in the folder. The links are created automatically by the build script, which looks through the folder for all the .md files. These links will be in the sidebar of every page, so I can go directly from any page in the wiki to any other. This would make for a very cluttered sidebar if my projects had hundreds of notes pages, but I’ve never needed more than a dozen or so.
Each page’s name is taken from top line of its .md file. The page links are sorted according to the file name, which is why the overview page is given the “aa-” prefix—I want it at the top of the list. I use this method of sorting to group similar pages in the list of links; inspection notes have an “ii-” prefix, lab notes have an “ll-” prefix, etc.
The project name and number in the header and the contact link in the sidebar come from the project.info file:
projname = Project Name
projnumber = 9999
contact = Apple:A1A2AA41-FA30-40AE-9925-FD6DB270B0A5%3AABPerson
This file defines variables that are used by the build script to create the pages. The projname and projnumber are obvious; the contact variable contains the name of the contact (“Apple” for the skeleton file) and its Address Book ID, separated by a colon. I described a script for extracting the ID earlier this month—this is where I use it. When you click on a contact link in the sidebar, the Address Book opens to the card for that entry.

This is convenient when I’m reviewing a project and want call or email my client.
Although the skeleton version of the project.info file has just one contact, a page can have any number of contact links. I just add more contact = lines to the file.
I can, of course, edit a page by going to the Finder, working my way to the appropriate notes folder, and opening the .md file in my text editor. But I’ve made it easier than that. The editor I use, TextMate, is the handler for special URLs of the form
txmt://open?url=file:///Users/drang/Desktop/notes/aa-overview.md
By including a link like that in the sidebar, I can just click on it and TextMate will open the .md file associated with the page. The bottom of the sidebar has a similar link to the project.info file.
I mentioned before that the HTML files in the notes folder are built statically, which means that, unlike a regular wiki, I have to do something to get them built. And what I need to do is run the make utility on the Makefile in the notes directory. This could be done through the Terminal, but I’ve made a simple TextMate command that runs make whenever I type Command-Option-Control-M.

There’s probably a clever way to use Folder Actions to run the Makefile whenever an .md file is added or changed, but I haven’t looked into that yet.
In summary, when I want to create a new wiki for project notes, I
- Drag the skeleton
notesfolder from my Desktop to the project folder. - Edit the
project.infoandaa-overview.mdfiles to include the appropriate information. - Add new
.mdfiles as my work on the project grows.
In my next post in this series, I’ll describe the template files and build scripts and will provide a zipfile with my skeleton notes folder.
Update
Part 3 is now up.
My no-server personal wiki—Part 1
June 24th, 2008
This is the first of what I expect to be a two- or three-part post on a wiki-like note taking system I’ve developed for keeping track of the work I do on my professional projects. I’ll start by explaining what I want out of such a system and how other solutions didn’t fit my needs.
At any given time, I’m working on several projects, each with its own client and its own set of facts, figures, and research results. My habit has always been to keep all computer files related to a particular project in its own folder (usually with subfolders) on my hard disk, just as I keep all physical files related to the project in a set of manila folders that are labeled and kept together in my file cabinets. Keeping everything related to a project together is important for three reasons:
- It’s just easier to keep track of things this way. Despite the improvements in Spotlight, dragging a file into a folder is less time-consuming than tagging it with a project name.
- Sometimes I need to copy all my work on a project and send it to the client. My paper files go off to a copy shop for photocopying, and my computer files get burned to DVD. If all the computer files are in one folder, burning a DVD is a one-step operation.
- When the project is done, I archive the computer files to DVD, put them with the paper files, and send them off to storage. Again, if all the computer files are in one folder, burning a DVD is a one-step operation.
Until recently, most of my project notes were on paper rather than in computer files. This was primarily because most of my notes are taken in the field, away from my computer, and there’s been no organizational advantage to rewriting those notes on the computer. But I did want the notes on the computer, so I began looking for ways to organize my notes that way.
At first, a wiki seemed like a natural fit. It’s easy to create new pages, and the pages are easy to navigate and edit. If I choose the right wiki software, I can use Markdown formatting, which I use to write almost everything these days. Unfortunately, the usual server-based wikis keep all the information in a central database, which means that my project notes would not be kept in the project folder. This makes it too difficult to archive the notes with the other project files, so server-based wikis were out.
The notion of a file-based wiki led me to TiddlyWiki and its various offshoots. Because it’s run with JavaScript, TiddlyWiki would let me keep my notes for a particular project in a single big HTML file in the project folder, just as I want. But there were two problems with TiddlyWiki: First, I didn’t like the default style and found its CSS structure very difficult to delve into and modify. Second, TiddlyWiki doesn’t work well with Safari because Safari’s JavaScript doesn’t like the idea of saving changes to the HTML file, which is essential to the idea of a wiki. (I tried using the Java applet that gets around this problem, but it didn’t work for me. I suspect I could have gotten it to work if I’d kept at it, but since I didn’t like the look of TiddlyWiki it didn’t seem worth the effort.)
So then I moved on to VoodooPad, Gus Mueller’s personal wiki application for the Mac. This seemed like the perfect solution. Its pages can be styled however I like, its data are saved to a file that can be put anywhere on my hard disk and can be exported to various open formats—this is important because I don’t want to get stuck in a proprietary system—and it’s backed by a developer known to be responsive to his customers. I tried it, I bought a license for it, but I just couldn’t get used to using it because it doesn’t use Markdown. I was a bit surprised at this reaction, but after a decade of using text-only systems (SGML, LaTeX, and now Markdown) I just couldn’t stand using something that works like a word processor. Eventually, I gave up and gave my copy of VoodooPad to my daughter to help her organize her college notes. Since it came from me, I suspect she’s ignored it—most parents of teenagers will understand that—but I still think VoodooPad would be a great solution for someone who likes writing in a word processor.
At this point, I decided to create my own system. The rules I set for myself were:
- It has to use text files that can be stored anywhere and are easily moved and archived.
- The notes are to be written in Markdown. If I later decide that Textile or reStructuredText or something else is better, changing to the new markup system should be easy.
- The notes are to be written in a text editor rather than in an HTML text box so I don’t feel like I’m writing in a straightjacket.
- The notes should be styled according to my taste. Since my taste can change, the style should be easy to change.
- The creation of new pages and new links to those pages should be simple and/or automatic.
I’ll start describing the system I came up with in the next post.
Update
Part 2 and Part 3 are now up.
Syncing contacts with Google and the “Sync” menu
May 29th, 2008
You’ve probably heard that the 10.5.3 update to Leopard allows you to sync your Address Book contacts with your GMail (or Google Apps) contacts. This is officially supported only if you have an iPhone or iPod Touch, but can apparently be done with a bit of plist editing even if you don’t own one.
I’m sure most people did their first sync with no trouble, but I made the mistake of looking at Address Book’s help page on the topic and didn’t read carefully. Step 5 of the “Synchronizing with Google Contacts” instructions is
Click the Sync menu in the menu bar and choose Sync Now.
My eyes went up to the Address Book menu bar and saw no menu named Sync and no menu item named Sync Now. Maybe Sync is a submenu? No. Maybe I read the instructions wrong? No. Maybe I didn’t read the next paragraph? Yes.
To add the Sync menu to the menu bar, open iSync, choose iSync > Preferences, and then select “Show status in menu bar.”
Oh, the Sync menu isn’t really named Sync, and it isn’t part of Address Book. It’s the Ouroboros-like iSync status menu over at the right side of the menu bar. The one I chose to keep hidden long ago because it’s practically useless.

In fact, I never did use the Sync Now command. I decided to just put my iPhone in the Dock and see what happened; it’s been my impression that iSync kind of runs in the background when my iPhone syncs. Success! Google syncing went ahead and I had to resolve a few minor conflicts.
Oddly enough, after my first iPhone/Google sync, the iSync menu appeared (which is how I got the screenshot above). I had to open iSync and uncheck the status menu preference to get it back to the way I like.

Update
Today (5/30) tried using the Sync Now command instead of just connecting my iPhone. I had cleaned up my Address Book and decided to delete all of my Google Contacts and start with a fresh sync. Because I was at home, and my iPhone is synced to my work computer, I couldn’t put the phone in its cradle. So I used Leopard’s screen sharing to access my work machine from my iBook, activated the iSync status menu, and selected Sync Now. Nothing. The arrowed circle spun a bit, but my list of contacts at Google stayed empty. Maybe Sync Now only works with .Mac?
Further update: Goodbye, Google syncing
After just having almost all my contacts deleted from Address Book and my iPhone during a “sync” with Google Contacts, I’ve turned off syncing with Google and don’t expect to turn it back on again. There was no warning from iSync, I just opened Address Book and found only 6 or 7 entries instead of the 700 or so that should have been there. I’d be really pissed if restoring from my backup weren’t so easy.
Praise for Library Elf
May 21st, 2008
I’ve been using Library Elf to keep track of my families library loans for a couple of years now, and it’s been one of those things that integrate so well with your life that you forget what it was when you didn’t have it. Recently I’ve learned that the people behind Library Elf are not only clever for coming up with a useful tool, they’re also dedicated to keeping their users happy.
First, some background: Library Elf is a web/email/rss service that polls your local library’s web site to keep track of the books (and CDs and movies) you’ve checked out and those you’ve put on hold. You can keep track by logging on to your account at libraryelf.com, by having emails sent to you, or by subscribing to an RSS feed. Library Elf presents the information in a very nice way, with a calendar showing upcoming due dates

and a set of tables showing your borrowings and holds in various categories (click for full size).
The best thing about the Elf for families is that you can keep track of several cards on one Elf account. These can be
- cards for one person issued by several libraries,
- cards for several people issued by one library, or
- cards for several people issued by several libraries.
This is especially useful for families. The status of Mom’s, Dad’s, and the kids’ items are all listed in one spot and everything that’s due soon can be rounded up to return on the next trip.
You can choose from among several notification schedules—weekly, daily, x days before an item is due, etc. From our one account, my wife and I get an email notice every day; we always know what’s coming up due and can consolidate our returns, making fewer trips.
So that’s why the Elf works so well for us. As I said, it quickly became a normal part of our routine, unnoticed until our local library revamped its web presence last month. The new URLs for the library’s holdings screwed up the Elf’s queries. I wrote an email to support@libraryelf.com (which was a guess, there’s no support address listed on the site), letting them know of the problem. Within a few days they had adjusted to the new system and we were back in business.
Late last week I discovered that holds ready for pickup were being placed in the Holds Not Ready Yet category. Another email went out to the Elf and the fix was delivered today. Great response!
Library Elf is free, supported by ads from Google and Amazon. If your library is on their supported list, you should look into setting up an account.
Formatting flight schedules for trip card
May 7th, 2008
In an earlier post, I described an OmniOutliner template for collecting itinerary information and printing it out on an index card. In this post, I’ll show a simple script that takes flight information from an airline web site and reformats it for the trip card.
One of the tedious parts of making an itinerary is putting the flight information into the right format. The format I like is reflected in the template, which has the departure time first, the arrival time second, and the flight number (or numbers, if it’s a connection) third. The times are right justified and the flight number is left justified.
Unfortunately, the airline web sites have their own ideas about the best way to present flight information, and because their ideas and mine don’t agree, I can’t just copy schedules from their web sites and paste them into my template. I can, however, write a script that does takes the information in the airline’s format and rearranges it into my format. Since I usually fly Southwest, that’s the format I’ve focused on.
Southwest likes to arrange its flight information in tabular form. Each row of the table represents a flight, with the flight numbers first, then its departure and arrival times, then a bunch of other information that I don’t particularly care about right now. What I want to be able to do is select some portion of this table from Southwest’s page

paste it into my OmniOutliner trip card template (using the Paste With Current Style command to avoid overwriting the template’s carefully chosen tab settings)

and then run the script that reformats the data.

Here’s the script. I call it “Reformat SW Schedule” and keep it in ~/Library/Scripts/Applications/OmniOutliner. By putting it there, FastScripts—which I use instead of the usual AppleScript menu—will make it available at the top of its menu when OmniOutliner is the active application.
1: #!/usr/bin/python
2:
3: from appscript import *
4: import re
5:
6: # Get the contents of the selected cell in the front document. It should
7: # contain the schedule as it comes from Southwest's site.
8: ooFront = app('OmniOutliner').document.get()[0]
9: selectedCell = ooFront.selected_rows[0].topic
10: swSchedule = selectedCell.get()
11:
12: # Reformat the Southwest schedule to match the trip card format.
13: flightInfo = re.compile('^(\S+)\s+(\S+)\s+(\S+).*$', re.MULTILINE)
14: def format(mo):
15: infoList = ['\t',
16: mo.group(2)[:-1], # departure time, w/o the "m"
17: '\t',
18: mo.group(3)[:-1], # arrival time, w/o the "m"
19: '\t',
20: 'SW ',
21: mo.group(1)] # flight number(s)
22: return ''.join(infoList)
23: sched = flightInfo.sub(format, swSchedule)
24:
25: # Put the reformatted schedule back into the selected cell.
26: selectedCell.set(sched)
The script expects the outline cell with the badly-formatted schedule to be selected. It takes the contents of that cell, reformats it, and replaces the contents with the reformatted version. It will work with one or more rows of information from the Southwest table.
The script uses the appscript Python library to communicate with OmniOutliner. I suppose I could have used AppleScript instead of Python, but this script is mostly text manipulation and I prefer Python’s text handling tools. As with every AppleScript or appscript program, the hardest part is learning the application’s unique set of scripting commands. That’s taken care of in Lines 8 and 9. Line 10 then puts the contents of the cell into a variable, Lines 13-23 transform it, and Line 26 puts the transformed version back into the cell.
If I start using another airline regularly, I’ll probably write a similar reformatter for it.
What’s in my Pelican?
May 6th, 2008
Last week I got a red Pelican 1060 Micro Case to carry my breakable and water-sensitive stuff in a saddlebag while I bike back and forth to work. For years I’ve just been wrapping my phone, wallet, USB thumb drive, etc in a plastic bag. This has worked, but when this spring’s stiff breezes blew my bike over a few times—fortunately with the saddlebags empty—I began to think my stuff needed better protection. That my old phone had been replaced by an iPhone gave me further incentive.
Pelican cases are pretty common among people in my business; they protect cameras, microscopes, and other delicate equipment from the abuses of the road. So they were my natural choice when I went looking for a case. The 1060 is the largest of the “micro” cases, which have clear tops and no handle. You fill them with Pelican’s “pick ’n’ pluck” foam, which you can customize to fit the outlines of the equipment you’re carrying.
So here’s how I fill my case. First, I put in my Fisher Space Pen, digital voice recorder, USB thumb drive, and keys. My Camry uses an electronic “Smart Key,” so that thing on the right that looks like a fob actually is the key for my car.

Then I add my iPhone above the Space Pen.

And my watch and earbuds on top of the phone. My earbuds are wrapped up in a short length of inner tube, which keeps them from tangling in my pocket.

Finally, I add my wallet and Levenger Shirt Pocket Briefcase. The SPB is an upscale replacement for the Hipster PDA; I prefer the SPB because it keeps the index cards a bit cleaner and doesn’t have a binder clip that pops off at inopportune times. Despite its name, I carry my SPB in my back pocket.

The wallet and SPB act as top padding and keep everything tight when I close the lid.

I haven’t included links to higher resolution versions of these photos because I took them without a flash to reduce reflections. The exposure times were about 1/5 of a second, so the originals are pretty fuzzy. Fortunately, the reduced sizes here look OK.




