It looks like somebody knocked my bike over at some point today, which scuffed up the right handgrip and bent the derailleur hanger. I'm annoyed because of careless people who knock over other people's bikes, and doubly annoyed because it's going to cost me a new derailleur hanger to fix this.
In order to follow Twitter, rather than having to reload the Twitter home page all the time or use a separate Twitter client, I was looking for a way to make tweets show up in an IRC channel. Originally I wrote an IRC "bot", which reloaded my Twitter page periodically and posted new tweets to an IRC channel. This was a bit fragile and wasn't a great solution, since it depends on connecting to some existing IRC network.
There is a project called BitlBee that is an IRC server that connects to various different IM networks (AIM, Jabber, etc). You connect your IRC client to your own local BitlBee server, which then connects to the IM networks of your choice. BitlBee is written in C and is therefore less easy to adapt and modify than if it were implemented in a more modern language.
I wanted to play with the Twitter Streaming API, so I wrote a Twitter-IRC gateway in Python called twig. Right now it does the simplest thing possible - it forwards tweets from the people you follow on Twitter into an IRC channel. It's a select-loop based single threaded implementation which should be easy to extend and modify.
If you use IRC and want to follow Twitter, check it out on Github.
My LiveJournal "friends" page looks pretty sad today. It's got 25 entries covering four days (back in the heyday of LJ, my friends list would typically roll over 25 entries in a day). There's one of my own entries, but as for the rest of them:
- Number of new posts in the last 24 hours: 0 (except for status telling everybody the site is still up)
- Number of posts by people I've actually met in real life: 0
- 12 entries by jwz (occasionally amusing but mostly videos I don't watch)
- 2 annoying "loudtwitter" crossposts
- 1 LJ news update from news
- 1 post where a mutual friend actually posts words they've written instead of just pictures.
LiveJournal = dead.
I usually only use my MP3 player (Creative Zen Stone Plus) to listen to podcasts when I take the bus to work. After the Christmas holiday break, I went to plug in my player to copy the latest podcasts to it, and it didn't power up. I tried the reset button on it, I tried "charging" it for a whole day, I tried everything suggested on the Creative troubleshooting site, and didn't get so much as a blink out of its little LED. It's possible that the battery was drained to a level below some threshold where it refuses to charge again (apparently that sometimes happens with Li-ion batteries).
I liked the player, so I found another identical one on Trademe (New Zealand's own version of Ebay). I charged it up, copied my current files to it, and it worked like a charm. For just two days. Then, as I was copying some more files to it, I got some odd I/O errors during copying, followed by generally slow performance (and USB timeout errors in my Macbook system.log file), followed by a complete loss of files on the device and and inability to boot it up (turning it on shows the "Creative" logo screen and nothing further). That was an unfortunate waste of $60.
I'm now on the hunt for a new player. One of the features I use on the player is the ability to delete a file while I'm listening to it. I do this whenever I'm done listening to a podcast, as unlike music the exception is wanting to keep the file. Anyway, a file delete operation is a must, and I never realised that this was apparently an uncommon feature. Fortunately, today virtually all manufacturers provide the full user manuals for their devices online for download. Because deleting files seems to be an obscure feature, it generally doesn't seem to be mentioned in the short blurbs.
- Sony Walkman - no delete function
- Philips GoGear - no delete function
- Samsung U4 - delete function, but not current file!
- Creative Zen Stone - delete function, including current file
I'm sort of having trouble finding other models because I know I don't want an iPod (I've written my own program to download and manage podcast feeds, so I need an ordinary filesystem interface). I also don't care about: video, photos, hackability (ie. I don't need to load Rockbox), more than about 4GB of space, or anything over about NZ$100.
I'm currently undecided between trying my luck with another Zen Stone from Trademe (as they don't seem to be sold at retail here anymore), or getting a Samsung U4 at retail so I can return/replace it if it's not working for me. Does anybody have any other ideas?
Last week the news started coming about regarding various computing system failures caused by the rollover to the year 2010. I wondered how easy it would be to identify such bugs in open source software, using Google Code Search. What kind of bug would be would be easy to identify? A common error in the last century was to use a C printf format string "19%d", which would roll over from 1999 to 19100 at the turn of the century.
What if people used "200%d" as a format string? That would roll over from 2009 to 20010 in the year 2010. But surely nobody would actually do that, right? Wrong. Some of those hits are false hits and not relevant to dates, but I found about 10 open source projects with such date-related format strings. Some of them are:
I've sent suggested patches to fix the bug(s) to each project that I could find.
I'm pretty sure this technique of using Google Code Search has been used to locate unsafe coding practices related to software security vulnerabilities, but I wonder whether anybody has successfully applied it to other types of software bugs.
2009 seems to have had even fewer changes than previous years. But it still had lots going on!
- Circumnavigated the globe for the first time. Amy had already done this once, and it's good to catch up.
- As a result of the above trip, I visited Germany, Ireland, Iceland (with the furthest from the equator I've ever been, past 66°N), London, and Tokyo for the first time.
- Amy and I had a big wedding reception (two years later!) with my extended family in Vancouver. Saw lots of people I hadn't seen for years.
- Attended SXSW as a participant for the first time. Plus, the seventh annual Nuclear Tacos at SXSW!
- Met Andy Hopper (the head of the Computer Technology Department at Cambridge University) through a string of coincidences, plus some work I did on VNC back in 1998.
- Presented a lightning talk on Psil at Kiwi PyCon.
- New open source software: pyqver (identify required version for Python code), emulino (Arduino emulator), mandelbrot set viewer, relight.
- Works in progress: psil, xearth.
One of the projects I have running is a temperature monitor. I built a QK145 temperature monitor kit a few years ago and have been monitoring local temperature data for a few years now. However, the process I have monitoring and logging the temperature occasionally crashes with a bus error or illegal instruction or some other weird error. I don't know whether it's related to the old version of FreeBSD running the server, or dodgy hardware (memory?), a broken driver, or what. It doesn't happen often enough to get concerned about (yet).
Anyway, I got annoyed with having to restart the monitor if it happened to fall over. The result is relight, a small Python script that automatically restarts a process that crashes occasionally. Here's the usage:
Usage: ./relight.py [options] command args ... -n restarts number of restarts within a minute before we give up (default 5) -l logfile name of log file (default relight.log) -w wait seconds to wait between restarts (default 5)
Relight also comes with complete unit tests! It was a bit tricky to write automated tests that deliberately killed a process spawned by a child process (a "grandchild" process). But by having the grandchild process echo its own pid, the test code was able to read that and send a SIGKILL to the correct process.
Flying with Fault Line Flyers in Texas was pretty much a no-brainer for me at the time. It was about US$23 for a tow, and time in the air (glider rental) was a flat $3 or so per flight. I was living by myself and had plenty of time and enough money to spend on a weekend activity.
Here, a similar tow is about NZ$50, and glider rental is just under $1 per minute of flying time. As you can imagine, that adds up extremely quickly and the reality is it exceeds what I can justify for a weekend activity today. Especially since I like to spend weekend time with my wife (as one or both of us often seem to be busy during weeknights).
Coming to this conclusion was tough because I truly enjoy flying, but was always conscious of how much it cost. Naturally, that dampened the enjoyment somewhat. I realised that there are two types of leisure activities: those that have a marginal cost, and those that don't. Activities with a marginal cost are those where you have to shell out some amount of cash every time you do whatever it is. Gliding is definitely one of these activities; skiing, skydiving, and golfing are other examples. On the other hand, activities without a marginal cost usually require you to purchase equipment of some kind, but doing the activity just once doesn't cost anything. There are many examples of this: cycling, surfing, hiking, fishing, diving, even things like sailing or motorcycling (where the initial cost might be substantial). I have discovered that I'm a no-marginal-cost kind of guy. (Having said that, I'll still go skiing!)
Speaking of gliding, congratulations to Terry Delore who just yesterday broke the world distance gliding record with a 2501 km flight!
I've only had a bit of time to work on the Psil compiler, but it's coming along well. The compiler now generates Python AST code for many kinds of examples.
As mentioned previously, I've tried annotating the AST with line and column information to help locate Python runtime errors. The representation of lists that I'm currently using (just a Python list) doesn't leave a lot of room to store the extra annotation information. For example, the code:
(print (+ foo 5))
is represented as the following Python lists:
[Symbol("print"), [Symbol("+"), Symbol("foo"), 5]]
There's not a lot of room in this representation to store source line annotations. The first thing I tried was to declare a global
DebugInfo dictionary, indexed by the
id() of the list (Python's
id() represents a unique identifier such as a machine address). So for example, the above debug info might be:
DebugInfo = [(1, 2), (1, 8)] DebugInfo = [(1, 9), (1, 11), (1, 15)]
DebugInfo represents the starting line and column of each element in the first (outer) list. The second
DebugInfo represents the same for the three elements of the inner list. This seemed like a great idea, and it was poised to work well for small examples. However, after some more complex examples particularly including macro expansion (very common in a Lisp language), the original code was garbage collected and the addresses of lists were re-used, causing the
DebugInfo addresses to align with different source lists! This was tricky to track down.
I've moved that code to another branch until I figure out what to do with it. I may be able to manage it by not letting the original code as read from the source be garbage collected (by keeping a reference somewhere else), that could work. The information only needs to be kept during the compile phase, as soon as it's embedded in the AST it doesn't need to hang around any longer.
Anyway, more work needed. Just writing this post helped me sort out some ideas. Source on GitHub.