Paul Calnan
Published August 28, 2013

I suspect I spend more time fiddling with my blogging setup than I spend actually blogging.

Back when I moved to Github Pages, I started using VoodooPad's static publishing engine. The output looked good but I didn't like the input format. Keeping a directory full of Markdown files that I can edit in Vim is preferable to using another editor.

After some looking around, I decided to try Pelican.

To extract my posts from VoodooPad, I wrote a Python script. It finds all published pages in a VoodooPad bundle directory, prepends some Markdown metadata tags (title, publish date, and slug), and writes the Markdown to a file. Here is the script:

I wanted to keep the site's file structure as similar to the current structure as possible. This included keeping the file slugs the same. Rather than trying to trick Pelican into deriving the original slugs, I added some code to my extraction script to pre-compute the slugs and include them in the Markdown metadata.

The only manual change I had to make to my content was to switch from code blocks that are indented by four spaces to fenced code blocks. This allows me to specify the language for the code block instead of relying on highlight.js to figure it out (often incorrectly).

The theme is more-or-less written from scratch. I liked the VoodooPad-generated site and had already made some customizations to it. It was fairly simple to port that over to use Pelican's templating system.

Published August 15, 2013

One of my clients uses a phone bridge for conference calls. I usually call in to the bridge using Skype. Each regular conference call I have uses a different access code. It works like an extension number: you call the bridge, wait a few seconds, dial the access code, press #, wait a few seconds, and press # again.

On a cell phone, you can usually add commas to the phone number to insert a pause when dialing, allowing you to save extensions and access codes like this in the contact information. Of course, Skype doesn't support that.

I found an AppleScript on a Skype discussion board that shows a way to dial a number using Skype followed by a DTMF string to be sent after the call connects. I wrote a Python wrapper for it. Commas are interpreted as 2 second delays.

Now, I can call the phone bridge and dial the access code all with the following command:

$ skypecall 800-555-1212 "12345#,,#"

This dials the number +18005551212, waits for the call to connect, waits 10 seconds, then dials the string 12345#, waits 4 seconds, then dials #.

Here's the Python script:

It's fairly easy to go from that to any of a number of shortcuts (Alfred, LaunchBar, an Automator action, etc.) to quickly place a call.

UPDATE: I created an Alfred Keyword action named bridge which triggers a shell script that looks like this:

The case statement maps from keyword arguments (monday, wednesday, or friday in this example) into access codes (12345, 23456, or 34567 respectively). To run it, I invoke Alfred (Cmd-Space on my computer) then I type:

bridge monday

This causes Skype to dial +18005551212, and enters the access code 12345 with the right pauses and #s. If I wanted to use an arbitrary access code that doesn't have a corresponding keyword, I could do so like this:

bridge 24680
Published August 5, 2013

Occasionally, I've wanted to be able to poke around in a plist file while working in the terminal. You can open an XML plist in a text editor like Vim, but a binary plist just looks like gibberish.

Fortunately, you can convert a plist file into XML format with the following command:

plutil -convert xml1 INPUT_FILENAME

Alternatively, you can convert a plist file into binary format with the following command:

plutil -convert binary1 INPUT_FILENAME

Obviously, change INPUT_FILENAME to whatever file you want to edit.

I wrote a quick Python script to automate this. I called it edit-plist. It first checks the file type (using the file utility). If it's a binary plist, it converts to XML. Then it opens in the selected editor (Vim). Once the editor exits, if the file was originally a binary plist, it converts back to that format.

Published August 2, 2013

I do a lot of work via SSH on a remote Linux server. It is often useful to transfer text from that server back to my local machine. Rather than save to a file and scp it down to my local machine, I adapted this process to allow me to copy to my local pasteboard from a remote machine.

Note, I use port 50730 for this. I can't remember why I picked that number. Regardless, it's arbitrary and you should be able to choose something else if you prefer.

Step 1: Create a pasteboard daemon

On Mac OS X, this is fairly easy using a Launch Agent.

Save the following XML property list file in ~/Library/LaunchAgents/com.paulcalnan.pbcopy.plist on your local machine:

Note that I use my domain name, com.paulcalnan, in the daemon and file name. You can call it whatever you like.

Step 2: Load the daemon

From the Terminal on your local machine, run:

launchctl load ~/Library/LaunchAgents/com.paulcalnan.pbcopy.plist

Step 3: Configure SSH port forwarding

Add the following to your local machine's ~/.ssh/config file:

RemoteForward 50730

Step 4: Create a remote pbcopy script

Add the following file to the remote server as ~/bin/pbcopy and make it executable:

#!/usr/bin/env bash
cat | nc localhost 50730

This assumes ~/bin is on your PATH. If the remote host runs OS X, you should name it something else, like rpbcopy, to prevent confusion with the built-in pbcopy.

Step 5: Try it out

From the remote server, run a command and pipe the output through pbcopy:

uptime | pbcopy

Back on your local machine, paste into a text editor.

Bonus tmux Trick

Most of the time, I use tmux to manage multiple consoles in the same SSH session. When I split the window horizontally, it breaks my ability to select multiple lines of text with the mouse.

To copy from a tmux session, I do a Ctrl-A [, select text I want to copy, and press Enter (I use Ctrl-A instead of Ctrl-B for my prefix). That puts the selected text in the tmux buffer. To copy the tmux buffer contents, I run tmuxcp, defined as an alias in my .bashrc:

alias tmuxcp='tmux save-buffer - | pbcopy'

This works on Linux (where I have my pbcopy script on my path) and on OS X (which has the native pbcopy on the path).


I use this quite often and it's turned out to be a huge time saver. It's not perfect, though. There are two issues I have encountered.

First, it doesn't work if you open multiple SSH sessions to the same server. After one session is opened, subsequent sessions print a warning:

Warning: remote port forwarding failed for listen port 50730

This can cause other issues. For instance, I have a particular Linux host I connect to via SSH that also runs a MySQL instance. if I have an SSH session open to that host and then use MySQL Workbench (or some other MySQL graphical client) to open an SSH connection to that same host, the warning message is incorrectly interpreted as an error message and the connection fails. The workaround here is to open the MySQL connection first and then open the SSH connection. The port forwarding will fail in the SSH session, preventing the remote pbcopy from working, but the MySQL connection will work.

Second, it doesn't handle text encoding particularly well. When I pass UTF-8 text into the remote pbcopy script, it shows up on the local pasteboard garbled. This shouldn't be too hard to fix, but I don't run into it often enough to spend the time debugging it.

Published August 2, 2013

Someone posted to Twitter a link to a presentation on Python iteration. In it, I saw something clever.

When iterating over a file line-by-line, you generally do something like this:

with open(some_filename, 'r') as fh:
    for line in fh:

Occasionally, you need a line number associated with each line of data. I usually wind up doing something like this:

with open(some_filename, 'r') as fh:
    lineno = 0
    for line in fh:
        lineno += 1
        do_something_interesting(line, lineno)

From the presentation, I learned that you can do the same with the enumerate function:

with open(some_filename, 'r') as fh:
    for lineno, line in enumerate(fh, start=1):
        do_something_interesting(line, lineno)

I can't believe that never occurred to me before.

Newer Posts | Older Posts