IRC, My Way

This is a post I’ve been meaning to write for a long time. I have a rather complicated setup involving multiple layers, but the end result is amazing. I maintain a 24/7 presence on the internet — on multiple IRC servers and instant messaging services — and I can send and receive messages from any computer or device I happen to be using at the time.

From any SSH client, I can seamlessly pick up my IRC session where I last left it, regardless of where I started that session. Similarly, I can connect with my phone’s IRC client, get a short backlog of recent conversations, or answer pending private messages. When I’m not already engaged in a conversation, I get near-instant notification on my phone and desktop, allowing me to respond at my leisure and from any location. I never miss a private message because I was connected from the wrong place, other users always see a single nick, and I get a central, searchable history of every channel and private message.

With this sort of setup, I gain a lot of freedom — to deal with conversations on my terms — and convenience. It’s served me well for a couple years, and I’ve enjoyed IRC much more since putting it all together. For each layer, I’ll detail the tasks it covers, the software I’ve chosen, and give a copy of any configuration files or options needed to replicate my environment.

Continue reading »

Air Force Museum Photos

Yesterday, my wife and I visited the National Museum of the United States Air Force at Wright-Patterson AFB in Dayton, Ohio. We walked through the three main hangars, mostly in chronological order. I snapped a lot of pictures along the way with my Nexus S; I picked out the blurry duplicates where possible, and captioned the photos as best I could. They actually turned out better than expected, considering the low light levels and how unsteady my arms got.

I didn’t get to take pictures of the XB-70 like I wanted to though; it was in their Research and Development hangar, which requires an ID check and bus ride to visit. Hopefully we’ll get to return soon and rectify that.

The full gallery is on Picasa, and contains 130 photos.

B-29 "Bockscar"
B-29 “Bockscar”

F-86 Saber
F-86 Saber

F-117 Nighthawk
F-117 Nighthawk

F-22 Raptor
F-22 Raptor

Spotify Gnome Integration

Spotify-Gnome is a program that provides Gnome media key support for the Spotify Linux client. It supports the play/pause, stop, next, and previous signals, and is compatible with both Gnome 2 and Gnome 3.

The Spotify client supports DBus for controlling the player, using the MPRIS Specification, but does not listen for basic media key signals provided by Gnome. This program acts as a “wrapper” around Spotify to translate media key signals from Gnome and send them to the Spotify client.

The program is released under the MIT license, and the source code and documentation can be found on the project’s Github repository page.

Many thanks to Mike Houston at and Fran Dieguez at Mabishu for their blog postings that pointed me in the right directions to get this implemented.

Source Integration Triage

When users are having troubles with setting up the source integration plugin with their repositories, I’ve found that there is a common set of pain points. I’m going to list them here, along with their respective solutions, in hopes that users can more easily find the fixes in the future. This post will be updated as new tips or advice arrive.


  • Linking changesets to issues requires commit messages to match the regular expressions specified in the source integration configuration page. By default, phrases like “fixes #123” or “resolved #123, #123” are supported, in present, past, singular, and plural forms.

  • Remote checkin must be enabled for use by post-commit hooks that don’t use an API key to authenticate, and must list the IP addresses or blocks for any repository server that will push commit data to Mantis.

  • Remote imports must be enabled for use by cronjob-based scripts that will trigger Mantis to pull in new changeset data for a given repository.


  • Your web server needs to have the SVN client binaries installed, and they must be accessible by the account that your web server uses. Similarly, if the binaries are in a directory that’s not included in your web server’s default path, you will need to specify the directory path in your source integration configuration. On Linux, this is usually /usr/bin or /usr/local/bin — on Windows, something like c:/path/to/subversion/bin is likely required.

  • For Windows servers, you may also need to enable the “Windows start” source integration option.

  • Make sure that the individual repository URL that you use for Mantis is the same URL you would use to checkout the repository when using an SVN client.

  • When using repositories that require authentication, make sure the username and password you enter in Mantis has read access to the entire repository.

  • If your repositories are hosted using HTTPS/SSL, and your server is using self-signed certificates, you will need to have SVN version 1.6 or newer installed, and you will need to enable the “Trust all SSL certs” option from source integration.

  • If your commit messages contain UTF-8 or other non-ASCII characters, or your system’s locale is not set to “en_US”, then you may need to look at issue #93 and #130 on my bug tracker for help modifying your server or SourceSVN plugin to use an appropriate encoding or locale.


  • If using Gitweb, versions newer than 1.6 may not work correctly, as the Gitweb plugin is scraping HTML from the viewer, and changes to the HTML structure will break the Gitweb plugin. The version of Gitweb in use on MantisForge is known to work with the plugin.

  • Using Github with private organization repositories is not yet supported. Private repositories for normal user accounts, however, is supported. Enter the username and API key from any Github account with access to the repository, and it should import correctly.

  • Using branches other than “master” will require you to modify the individual repository configuration in Mantis to list any branches that you want to be imported.

Favorite Android Apps

This past Friday, I bought the new Samsung Galaxy Tab 10.1, and I absolutely love it. The new Honeycomb interface looks amazing, and is quite an improvement over what’s available on my Nexus S with Gingerbread. I love that the back, home, and task switching buttons are now rendered on the screen instead of having hardware buttons, and combining those buttons into the notification and status bar means you don’t even lose screen space compared to previous versions. The new application switcher looks really nice, but does seem to have some odd behaviors, like not showing the browser that I just switched away from, or seemingly choosing at random whether to display the list from the top instead of from the bottom where you would expect.

There are a lot of applications that don’t yet take advantage of what’s offered by the Honeycomb APIs, but still tend to work really well. It mainly depends on how well the author designed the application to scale with the user’s screen size and density. An example of doing it wrong is the official Facebook app; it’s still usable mind you, but it certainly looks dumb in process, showing the main menu as a large grid of tiny icons with massive amounts of whitespace between them. It would have gone a long way if they had simply scaled the images to fill the screen.

I’ve been meaning to write about some of my most cherished apps, and seeing them in new form has given me an even better reason to get to it. Some of them really only work well on a phone, and others have only gotten better than ever when given a tablet form factor to call their own. So in no particular order, here are my favorite apps for Android. All prices are rounded up from Market estimates at time of writing, and all screenshots are taken from my devices:

Continue reading »

Source Integration API Keys

Today marks an incremental release to the Source Integration plugin framework for MantisBT, now at version 0.16.3. This marks the introduction of support for using an API key to authorize inbound changeset data from repository data sources. It is initially supported for integration with Github, where large array of servers made it all but impossible to whitelist allowed IPs for remote commit data.

Future plans for the feature include support for configuring multiple API keys simultaneously, as well as adding support for using the API keys from other data sources, such as SVN or Gitweb repositories. Additionally, the old options for listing allowed IP addresses is now considered deprecated, and will likely be removed entirely at the next major release.

To set up an API key in your MantisBT instance, visit the Repository Configuration page, where you will find a new option labelled, strangely enough, “API Key”. You will need to generate your own key; the best way to do this is on a machine with OpenSSL by running the following command to create a secure, random string of hexadecimal digits, and then copying the resulting string to MantisBT:

$ openssl rand -hex 12

Once this is done, you can enable this on your Github projects by visiting the Service Hooks admin page for your repositories, activating the MantisBT hook, and copying the same key string into the “Api Key” field there. Any future pushes to your Github repo should send data to your MantisBT install using the API key to authorize the data submission.

Python: Using KeyboardInterrupt with a Multiprocessing Pool

I’ve recently been working on a parallel processing task in Python, using the multiprocessing module’s Pool class to manage multiple worker processes. Work comes in large batches, so there are frequent periods (especially right after startup) where all of the workers are idle. Unfortunately, when workers are idle, Python’s KeyboardInterrupt is not handled correctly by the multiprocessing module, which results in not only a lot of stacktraces spewed to the console, but also means the parent process will hang indefinitely.

There is quite a lot of suggestions for mitigating this issue, such as given in this question on Stack Overflow. Many places point to Bryce Boe’s article, where he advocates rolling your own replacement for the multiprocessing module’s Pool class, but that seems to not only invite bugs and added maintenance overhead, but also doesn’t address the root cause.

I have figured out (what I think is) a better solution to the problem, and have not found anyone else mentioning it online, so I have decided to share that here. It not only solves the problem of handling the interrupt for both idle and busy worker processes, but also precludes the need for worker processes to even care about KeyboardInterrupt in the first place.

The solution is to prevent the child processes from ever receiving KeyboardInterrupt in the first place, and leaving it completely up to the parent process to catch the interrupt and clean up the process pool as it sees fit. In my opinion this is the most optimal solution, because it reduces the amount of error handling code in the child process, and prevents needless error spew from idle workers.

The following example shows how to do this, and how it works with both idle and busy workers:

#!/usr/bin/env python

# Copyright (c) 2011 John Reese
# Licensed under the MIT License

import multiprocessing
import os
import signal
import time

def init_worker():
    signal.signal(signal.SIGINT, signal.SIG_IGN)

def run_worker():

def main():
    print "Initializng 5 workers"
    pool = multiprocessing.Pool(5, init_worker)

    print "Starting 3 jobs of 15 seconds each"
    for i in range(3):

        print "Waiting 10 seconds"

    except KeyboardInterrupt:
        print "Caught KeyboardInterrupt, terminating workers"

        print "Quitting normally"

if __name__ == "__main__":

This code is also available on Github as jreese/multiprocessing-keyboardinterrupt. If you think there’s a better way to accomplish this, please feel free to fork it and submit a pull request. Otherwise, hopefully this helps settle this issue for good.

Job Spam

Things that make it obvious that your “job offer” is just a piece of spam you’re throwing at the wall to see what sticks:

  • Saying you found my resume on or some other job site when I have never ever registered or even visited the site in question.

  • Saying you found my resume on a site I did sign up for, and then blatently ignoring that my account is marked as “not willing to relocate” and offering me a job in backwater Arkansas, Montana, Tennessee, or South Dakota. There is exactly one place I want to relocate to, and that is the west coast.

  • Requiring knowledge in technologies that aren’t even mentioned in passing on my resume.

  • Looking for “Rock Start” software engineers to join a start-up.

  • Advertising your start-up with a bullet point of “e-commerce… e-commerce… e-commerce”.

  • Having your offer email include a footnote saying “Message sent with an unregistered version of MailList King!”. Nothing says legitimate like a recruiter who uses an unregistered piece of spam software.



Fred Wilson’s recent post on Locale for Android was on Hacker News today, and although I commented there on why I like Locale, I want to expound on that a bit further.

I bought the very first Android phone, the T-Mobile G1, when it was first released over two years ago. Even then, Locale was big news for the platform, having won the very first Android Developer Challenge. I have been using it on all my Android phones since then, and I continue to be impressed by it.

Locale is the killer app for Android. It embodies everything that Android is capable of, and everything that Apple refuses to allow in iOS. My phone can now be smart enough that I don’t have to babysit its settings everywhere I go; it knows when to be discreet and when to be secure. No other mobile OS can do that.

For a quick background, Locale is an application for automating changes to your phone’s settings based on a configurable set of “situations”. You define a set of “defaults”, and then each situation is comprised of a set of “conditions” and “settings”. When a situation’s conditions are met, the associated settings override the defaults; when the conditions are no longer met, Locale returns to the default settings. By combining multiple situations together in a priority list, your phone can make intelligent decisions, and seamlessly switch between multiple situations as they become active or inactive.

But what makes Locale even better is that it was designed from the beginning to be extensible. You can find plugins on the Market that add new conditions and settings. Because of Android’s ability to share data between applications, these plugins can even go so far as to use context from, or modify behavior of, other applications installed on your phone. As an example, the Astrid task manager allows you to attach a location to your tasks, and integrates with Locale as a condition when you reach those locations.

But for a more concrete example of just what’s possible, I’d like to show you what my current Locale conditions and settings are.

  • Defaults: Wifi off, Ringer volume 85%, Vibrate on, Media volume 70%, Password lockscreen on
  • Night (Time 10pm-7am): Ringer off, Vibrate off
  • Work (Location): Wifi on, Ringer off, Vibrate on,
  • Headphones (Headphones connected): Media volume 20%
  • Home (Location): Wifi on, Ringer volume 100%, Password lockscreen off

The Locale plugins that I use to accomplish this:

Color me happy.

Kitty Cat One

I just got three new toys to play with at work, sitting in a server room, just waiting for me to have fun with them. Here’s a screenshot of me running htop on the first one; it’s current hostname is “kittycat1”…

screenshot of htop on kittycat1

Not exactly the shabbiest set of servers to work on…

Open Source talk on Podcast 17

On Saturday, I appeared as a guest host on Podcast 17, for the interview portion of episode #128, to talk about the benefits and challenges of creating open source modifications for Valve’s Source engine, the power behind their classic Half Life 2 series. It got rather sidetracked from the original plan of discussion, and ran longer than expected, but there was some interesting discussion, and great insight from former Valve contractor Tony Sergi.

If you work on the Source engine, or are looking to run or join open source mod projects, I highly recommend you take the time to listen in.

New Domain

For multiple reasons, I’ve decided to move away from using my domain for my online identity and begin using instead. I will be slowing moving over my sites and applications, and will make sure to set up 301 permanent redirects or other forwarding methods as necessary to make sure nothing gets orphaned for the forseeable future.

As for the actual reasoning behind the move, it stems from multiple issues I had with the old domain, such as:

  • Being able to pronounce my email address and domain to the general public without having to always spell it out and make sure they catch that there are two e’s in the domain.

  • Switching at the same time from jreese@ to john@ for my address also means I don’t have to worry about people misspelling my last name, which happens so much even my own family still gets it wrong on a regular basis.

  • Not having to explain what “leet” is, or getting remarks about it being a juvenile choice due to the stigma of “leetspeak”.

  • It’s a short .com domain, so that people will get it right every time; I’ve had people assume I actually meant, without confirming it before sending a doomed message…

Anyways, in the off chance that you’re a sentient being, and actually reading this, if you happen to catch an error or gap in my redirection efforts, please drop a line to john@ this domain.

ZNC to Notifo

Update: ZNC to Notifo has been renamed to ZNC Push, and given support for multiple push notifications services, including Boxcar and Prowl. Please update your links to the new ZNC Push page.

ZNC to Notifo is a module for ZNC that will send notifications to a Notifo account for any private message or channel highlight that matches a configurable set of conditions, including the user’s /away status, time since the last notification, number of clients connected to ZNC, and more.

The module is released under the MIT license, and the source code and documentation can be found on the project’s Github repository page.


Yesterday evening, I received sorrowful news. My neighbor had passed away in her sleep, to the surprise of everyone who knew her. An active grandmother, her personality exuded a quiet energy, a presence that brightened your day and made you smile. The loss is palpable.

Rest in peace, Joyce. You will be missed.

Android is Open

I am biased. But hopefully I can still be insightful and argue this point. This was sparked by a thread on Hacker News, in which someone commented:

Android is all but open.

I’m calling this out. Android, as a software project, is completely, 100%, open. It’s released by Google with the Apache license, which is recognized by OSI and the FSF as a Free/Libre, Open Source license. The Android code itself is freely available, freely redistributable, and can be compiled and flashed onto any compatible device.

However, there is a significant portion of the Android ecosystem that is not “open” by the same definitions above:

  • Device drivers for individual phones are open or closed depending on the device and the individual chipsets in question, but that is a moot point in my opinion as there are plenty of people who use Free desktop operating systems with closed “binary” drivers. Therefore I will leave this topic for another discussion.

  • All of the Google-branded applications — including the Market, Gmail, and Maps — are closed-source and must be licensed with Google to be included on a phone. This means that Cyanogen is not allowed to include these apps when he releases his amazing CyanogenMod firmware. Other services that Google then builds on top of these closed applications are also closed by nature, including their proprietary “push” communication model.

For some purists, this is a major problem, and I would generally agree. But unlike Apple and iOS devices, none of these Google-branded apps are “privileged” applications; they don’t get special treatment from Android, and they don’t have access to anything that “normal” applications can’t access through the SDK.

But more importantly, these apps are not Android, and they are not necessary to delivering an Android phone or firmware. Developers can write and release competing or nearly indentical applications that replace these closed system apps, and indeed, there are multiple competing “app stores” for Android, with Amazon rumored to be creating yet another. There are even better alternatives for Chrome to Phone already available. And if you insist on not using — or have a phone without — the Android Market, Android is perfectly capable of “side-loading” software packages, and nobody needs to pay Google for the rights to do so.

What is all this proclaimed openness worth if it still boils down to exploiting security systems if you want to run that system you just modified?

That is the real problem, and in my opinion the blame is firmly with the carriers; not Google, and certainly not Android. I specifically purchased a Nexus One because it supports the ability to flash the phone with unsigned firmware. I can download the Android source code, compile it, and flash that resulting firmware to my phone, without needing to root, exploit, or jailbreak my phone. I could do that with my Openmoko Freerunner, and I can do that with my Nexus One.

If enough people insisted on purchasing phones with this capability, then the carriers and manufacturers would pay attention and deliver. Or perhaps Google should be standing up to carriers and demanding that all Google-branded and licensed Android phones have this capability. But even if they could get away with that demand, they can’t enforce it on all Android devices; the very definition of Free Software allows carriers and manufacturers to take Android and do what they want with it if they don’t like Google’s terms.

Maybe the real lesson is that Free Software is a double-edged sword, and if you want corporations to join in, you have to be willing to play their game too.