Category Archives: Development

iPhone Brighton Buses webapp/javascript front-end

Here in Brighton a good number of the bus stops have electronic boards, that tell you when the next buses are due. The data for these boards is available online and even provides data for stops that don’t have the electronic boards. In fact there’s an free iPhone app available, so you can get the data easily on the move.

Brighton Station (Stop B)

After playing around with iPhone javascript apps, I thought it would be interesting to try and create a javascript app for the bus times. I had some specific ideas about how I wanted the app to work. I was also keen on trying out some more “HTML 5” tech. Plus I do like things to be (at least in principle) cross-platform, so this has a chance of working ok on Android phones (though I’ve not tested it on one).

There are still a few rough edges, but you can try out the app yourself at:

It will prompt you to add a stop. If you type in the text field, you’ll get a list of stops that match. If your browser supports geo-location, you’ll also see a “Find nearby” button, which will list the nearest few stops.

I had the pleasure of demoing this app at the Async Javascript show’n’tell last month. I quickly outlined how it worked, which involves the following:

Getting the data

The site has an API, which I used to scrape all of the bus stops in Brighton. I chose to scrape the update data from the website itself though, as I couldn’t get the API to give me the combined services for each stop (so you can see when the next 7 and 81 are coming for example). There are typically two stops for each name – one either side of the road. The updates are for both directions, so I actually merged the stops together – which makes searching easier.

All of the stop data was stored in a single SQLite database – mostly for convenience. The database is used in a read-only method in the actual running app. I’m sure I could use something a bit better, particularly when it comes to the distance queries. Currently, as there are a relatively small number of stops I’m using a brute force method to find the nearest stops, but I’m sure with the use of a proper spatial index this could be done a lot more efficiently. If this was scaled up to work for all stops in the UK, then that would be a necessity.


Initially the geo-location was pretty straightforward – I simply used the getCurrentPosition function and I got a latitude and longitude back. Testing in Firefox and Safari on the mac gave fairly reasonable results. However on the iPhone itself I started to notice it wasn’t very accurate. Sometimes it was out by several 100 metres, meaning that stops I was standing next to were sometimes not showing up at all! I had noticed, in the past, that the built-in map app sometimes has a bit of “lag” in getting an accurate position. So I switched to using watchPosition and polling for the position for several seconds. This worked pretty well, as the initial result would only be vaguely in the right place and then after a few seconds the position would become more accurate and the listing of nearby stops would start to look more sensible.

Look and feel

Originally I’d planned to mimic the look and feel of the iPhone’s built-in weather app. The app is built around a similar concept – you search for bus stops and add them to a list of stops that you can flick through. I tried to get a nice animated sliding action working, but kept on running into trouble on the device itself. In Safari and Firefox the animation all worked ok, but I suspect there’s an issue on the iPhone when you are dragging an area that limits redrawing. In the end I had to ditch the flip/swipe gesture too – interfering with the touch events again seemed to cause some rendering issues on occasion. So instead simply clicking on the left or right of the timetable moves between pages. It’s a slightly less complicated way of doing things, so there’s less that can go wrong really.

Old Brighton No. 5 Bus


As this was a nice simple app (on the back-end at least), I decided to take a little time to create a Fabric file to control deployment. The app is hosted on Webfaction, where I have already setup key-based login for ssh. The app is deployed using mod_wsgi with a daemon process, so that one merely needs to copy over the new code, then “touch” the .wsgi file restart the daemon process. Not exactly tricky to do, but making it a one-button process saves making any mistakes.

To trigger the deployment I run my fab file like this:

fab --user=lilspikey deploy:webapps/buses/app/

I actually have that in a shell script, that isn’t checked into git, so that the deployment specific username, host name and remote directory aren’t checked into source control. If I wasn’t using key-based login, I’d need to specify a password and I definitely wouldn’t want to check that into git!

Source code

You can get the source code on github in my buses repository.

Chumby to Arduino communication using PySerial

So here are a few notes on getting a Chumby to talk to an Arduino using PySerial (and Python). It’s pretty easy, but I’ll document it to make it obvious. As the Chumby is sometimes a bit slow with a few of these steps, it’s good to know it will work in the end.

First you’ll want Python on the Chumby. At the time the latest version already compiled for the Chumby is Python 2.6, so it’s pretty up-to-date.

Once you’ve got Python installed and on a USB stick you’ll also want to download PySerial – I picked the latest version PySerial-2.5-rc2.

With PySerial expanded and on the USB stick (alongside Python) you’ll want to put the USB stick in the Chumby and connect to it via SSH.

Change to the directory for the USB stick (e.g. cd /mnt/usb).

You should see (at least) two directories, one for Python and one for PySerial:

chumby:/mnt/usb-EC5C-3D0A# ls -l
drwxr-xr-x    6 root     root         4096 Jun 26 21:15 pyserial-2.5-rc2
drwxrwxrwx    4 root     root         4096 Jan 10 13:51 python2.6-chumby

You’re first instinct may be to try and install PySerial via the usual call to python install. However this appears not to work.

All is not lost though – just manually copy the relevant directory (serial) from PySerial to the python site-packages directory, e.g.:

cp -r pyserial-2.5-rc2/serial python2.6-chumby/lib/python2.6/site-packages/

Know to check that’s worked open a python prompt and try to import the serial library:

chumby:/mnt/usb-EC5C-3D0A# python2.6-chumby/bin/python
Python 2.6.2 (r262:71600, May 23 2009, 22:28:43) 
[GCC 4.3.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import serial

If you don’t see any errors (as above) then everything has installed ok.

Next step is to try out connecting an Arduino.

So first off you’ll want to ensure the Arduino has a program that can read from the serial port – to show that everything is working ok. In my case I picked my Morse Code program. This will read bytes from the serial port and toggle the built-in LED (on pin 13), so it’s handy for verifying the serial port is working.

So now you have a program loaded on the Arduino, connect it to the Chumby. The Arduino should get enough power from the Chumby to start up ok.

You need to work out which serial port the Arduino is using on the Chumby. List the tty’s in /dev and pick the most likely looking one (should have USB in it’s name):

chumby:/mnt/usb-EC5C-3D0A# ls /dev/tty*
/dev/tty      /dev/ttyS00   /dev/ttyS02   /dev/ttyS1    /dev/ttyS3
/dev/ttyS0    /dev/ttyS01   /dev/ttyS03   /dev/ttyS2    /dev/ttyUSB0

On my Chumby the serial port was /dev/ttyUSB0.

Now open up a python prompt again and try talking to the Arduino. You’ll need to configure the baud-rate of the serial port to match the program on the Chumby. In my case this was 9600.

chumby:/mnt/usb-EC5C-3D0A# python2.6-chumby/bin/python
Python 2.6.2 (r262:71600, May 23 2009, 22:28:43) 
[GCC 4.3.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import serial
>>> ser = serial.Serial('/dev/ttyUSB0', 9600, timeout=1)   
>>> ser.write('sos')

If you are using the same morse code program you should see the LED blink out ‘DOT-DOT-DOT DASH-DASH-DASH DOT-DOT-DOT’ – confirming that the serial port works.

This is really quite handy, as the Chumby is a small low-power Linux server. Coupled with Python this means it’s really easy to get any Arduino based project online, without needing a “normal” computer constantly running. Not quite as self-contained as using an Ethernet Shield, but the Chumby is fairly small, so it and an Arduino will easily sit on a window ledge (for example).

Arduino Tone Generator/”Theremin”

So here’s another quick Arduino project. It is a “theremin” of sorts, but whereas a real theremin uses antennas to control pitch and volume this on uses a potentiometer for pitch and a push button for volume. The tone is output via a piezo buzzer (as used for generating morse tones in the previous project).

Arduino "Theremin"

The voltage from the potentiometer is read via analogRead, then is mapped to a freqency to output on the buzzer. To make things sound nicer the frequencies are limited to the twelve “well tempered” notes. As the potentiometer is turned the note played changes. There’s a little bit of smoothing (legato) in between note transitions too (so it sounds a bit more theremin-like).

All code for this Arduino “theremin” is available on github, as part of my Arduino Sketches project.

Here’s a demo of the tone generator in action:

My First Arduino Project (Morse Code)

So I finally have an Arduino. I’ve been hankering after one for a while now, after seeing what Build Brighton and others have been able to do with them. So I was very happy when my better half paid attention to the hints I’d been dropping and got me an Arduino starter kit for my birthday. That was only a few days ago and thanks to how wonderfully easy the Arduino IDE is, it hasn’t taken long for me to get things working. The simplicity of writing the code, hitting upload and seeing the effect on the Arduino within seconds makes it really quick to try out different ideas. The only bit that’s tricky (for me at least) is the electronics side of things. Due to a slight fear of accidentally burning out the 8bit AVR chip at the core of the Arduino I’m being super cautious. Though this is due to my at best high school knowledge of electronics. That and the fact that I’m pretty much a software boy.

So what to make first? Well morse code seemed like a good starting point. I’d written an app to output morse on the capslock LED before and the starter kit had LEDs, so it seeded like a good starting point. On closer inspection there was also a piezoelectric buzzer – so even better it was possible to generate a tone too!

Getting the LED to turn on and off was pretty easy and it forms the standard “hello world” program for the Arduino. Getting the buzzer to generate a tone was marginally trickier, but not that hard and basically just consisted of turning it on and off quick enough to cause a vibration and therefore make a sound. With the help of this guide to making the Arduino play the Can-Can I also had details of how to wire the circuit correctly (in particular adding in a suitable resistor to avoid overloading the AVR chip).

Using the starter kits breadboard, jumper wires, a 330 Ohm resistor, an LED and the piezoelectric buzzer I put together this:

Arduino Morse Code Circuit

The buzzer had it’s positive pin wired in to pin 4 on the Arduino and the LED was in turn wired in to pin 13. In the picture above, I arbitrarily used yellow jumper leads for “ground” and green for positive. So one green lead goes to each pin (4 and 13) and only one yellow lead goes to the “ground” on the Arduino.

Initially I hard-coded the message the Arduino was going to output, but having to re-compile each time to change the message seemed a little tedious. So I decided to get the Arduino to read from the serial port, store the characters it read in, then output the relevant morse. To achieve this the program has a 512 byte buffer that it fills up with data read from the serial port. If the buffer is full it signals this by writing back a -1 down the serial port – otherwise it echos back what it has read in. As it plays the morse it moves along the buffer looking for the next character. Once all characters are output it resets the buffer. The program is actually able to read from the serial port whilst it is turning the LED on/off and generating tones. It’s only limited by the size of the buffer it is using and the fact that it can read faster from the serial port than it can output morse code.

Most of the work in the code revolved around trying to both read from the serial port and generate tones. If the morse was known ahead of time, it would be pretty easy to right several for-loops to run through each character generating tones until we were finished. However the program would not start reading from the serial port until it had finished outputting the morse. So apart from using some basic state-machine style antics to keep track of which character we were on and whether we were currently during a dot, dash or silent period the major a-ha moment for me was realizing how to easily generate a consistent tones without using delays in the code. In previous code I’d seen for generating tones, the code looked like:

for (long i=0; i < numCycles; i++){
    digitalWrite(targetPin,HIGH); // write the buzzer pin high to push out the diaphram
    delayMicroseconds(delayValue); // wait for the calculated delay value
    digitalWrite(targetPin,LOW); // write the buzzer pin low to pull back the diaphram
    delayMicroseconds(delayValue); // wait againf or the calculated delay value

This is nice and easy to follow, but all those calls to delayMicroseconds mean you are hanging around waiting for the air to move to make a sound.

As I wasn't too concerned with the particular fidelity of the sound from the buzzer I opted for the following instead:

void morse_pulse_on() {
  digitalWrite(LED_PIN, HIGH);
  unsigned long period = micros() % buzzer_delay;
  digitalWrite(BUZZER_PIN, period < (buzzer_delay>>1)? HIGH : LOW);

This was called every time through the loop() function if a sound needed to be played. As there is no delay in calling it, one could then immediately perform other tasks, such as checking for new serial data or turning the LED on and off. It's quite simple real - the modulus operator (%) is used to get the sub-divide the current time in microseconds into a number between 0 and buzzer_delay (a value pre-calculated to let us generate the right frequency) representing the current "period". If we are halfway through this period then we set the buzzer to HIGH, otherwise we set it to LOW. By repeatedly calling morse_pulse_on we end up with (in this case) a glorious 700Hz tone.

All code for this Arduino morse code program is available on github, as part of my Arduino Sketches project. Hopefully I'll add more code to that project as I get a chance to delve deeper into what the Arduino can do.

Here's a demo of the whole thing in action:

UPDATE: not long after finishing this, I discovered the tone and noTone functions. These produce a better tone than the technique outlined above. Though they do involve use of one of the interrupts on the arduino, that's normally used for PWM on pins 3 and 11 - not that it's a problem for this project.

Chumby Podcast Client Source Code

Ok so I blogged about a podcatcher/podcast client for the Chumby quite a while ago (August 2008 to be precise). At the time I said I’d tidy things up and release the source code etc. Well that didn’t quite happen, but I figured I might as well release the source code. So seeing as I’ve been using git a lot lately and github is easy to use I thought that’d I’d best just put online what I had.

So you can now find the hybrid Python, Javascript and Flash Chumby postcast client I dubbed chumbycast, on github. I’m providing the code just for the curious – I’ve had at least one request for it, but I’m not really going to detail too much of how it works. Though some of this is outlined in the original post where I mentioned the project.

I am tempted to revive this project a bit, but probably by trying a different approach. I mostly gave up on this as I was creating a UI on the Chumby in Flash and my Flash skills aren’t exactly great, plus I was trying to use mtasc which hampered things further. Which is not to belittle mtasc – it’s just with limited time and no previous Flash experience I wasn’t exactly helping myself by not using some nice friendly Flash IDE.

I’ve since realised that if I ditched the Flash UI I could probably get quite a bit done. The Python httpserver side of things was pretty easy. So if I focussed on that I would then have a few of ways of providing a UI by hijacking existing functionality on the Chumby.

  • The Chumby runs a httpserver on port 8080 when an ipod is plugged in, which the UI uses to access playlists etc. I could mimic this approach and effectively make the podcast client look like an iPod as far as the Chumby’s UI was concerned. By plugging in a USB stick loaded up with the podcast client everything would behave the same as if you had plugged in an iPod.
  • It’s possible to create playlist files and edit the “My Streams” section programmatically. Each podcast subscribed to would create a matching pls or m3u file and be added to the “My Streams” section.
  • Create a javascript/web UI for controlling the playback and subscriptions to podcasts and other podcast management tasks (like removing old files, manually downloading older episodes etc) from another computer. Possibly adding bonjour/zero-conf support so the Chumby can be browsed to easily

I would need to see whether those first two could be made to work for my purpose, but it would make sense to just use the existing UI on the Chumby – rather than creating a new one. The existing chumbycast code already provides a javascript/web UI for controlling the playback on the Chumby. This was originally done so I could remote control the chumby, but also so that I could easily create and debug an API for the Flash UI to use.

The other major missing feature is allowing the podcasts to be paused part way through. The current client does not support this, as the audio files are streamed and not downloaded. So that would be the first change to make. Now that I’ve dug out the code maybe I’ll be inspired to play around some more. I’ve also been listening to a lot more podcasts (thanks to Huffduffer) so it might happen yet.

Django Batch Select

So quite a while ago I wrote about avoiding the n+1 query problem with SQLObject. I’ve since been using Django a lot more. In particular at my day job I’ve been improving a Django site we’ve inherited. This particular site suffered from a few too many SQL queries and needed speeding up. Some of the issues related to the classic n+1 problem. i.e. one initial query triggering a further n queries (where n is the number of results in the first query).

A liberal dose of select_related helped. However that was only useful in the cases where a ForeignKey needed to be pre-fetched.

In the case however there was a page that was selecting a set of objects that had tags. The tags for each object were being displayed along side a link to the main object. Given that the initial query returned over three hundred objects, this meant the page was performing another three hundred (plus) queries to fetch the individual tags for each object! Now we could cache the page and that’s was indeed what was being done. The trouble however was when the cache expired. It also made things painful when developing – as I’d typically want to disable caching whilst I’m making changes to pages frequently.

I came up with a specific solution for this project – to perform the initial query, then a second query to fetch *all* of the other tags in one go. The results of the second query could then be stitched into the original results, to make them available in a handy manor within the page’s template.

I took the original idea and made it re-usable and am now releasing that code as Django Batch Select. There are examples of how to use it over at github, but it works a bit like this:

>>> entries = Entry.objects.batch_select('tags').all()
>>> entry = entries[0]
>>> print entry.tags_all
[<Tag: Tag object>]

It’s a very early release – after the result of only a few hours coding, so use with care. It does have 100% test code coverage at the moment and I’m reasonable confident about it working. Please try it out and let me know whether it works for you.

Kite Physics Demo

I’ve been working on a little kite physics demo app:

After chatting with Allistar at the £5app about how he did physics simulations I was pointed at “Gauss-Seidel” as an easy way to handle constraints. This led me to Advanced Character Physics by Thomas Jakobsen, which explained it all very nicely. That coupled with some info from NASA on forces on a kite helped me create this simple 2D “simulation”.

It’s not yet finished, but I thought I’d share some of my progress. I want to turn it into a slightly more rounded demo or perhaps even a simple game of some sort, with some scenery etc. I’m quite happy with how it’s turned out so far – even though I did waste a fair bit of time getting drop-shadows working…

It’s all written in Java, so it’ll be nice and easy to put online later. I think I’ll probably release the source too, as the physics and constraints code is fairly generalized. In fact through the use of generics and a few other tricks the code is setup to allow (potential) re-use for 3D physics too.

An iPhone friendly, local storage backed, offline TODO list webapp

A while back I had a go at using the local storage features being added to javascript to create a simple TODO list app. The main focus of the app was getting it all to fit under 5K (5120 bytes), but it was a good test of using a client-side sql database in javascript.

As the app was written for size it didn’t have many frills. It did however work on the iPhone, as it’s version of Safari had support for the openDatabase call needed. However it didn’t look so good and although the TODO list items were stored locally the phone still had to be online to access the host webpage – which kind of undermined some of it’s utility.

With my recent acquisition of an iPhone I thought I’d revisit this TODO app and make it play nicely on the iPhone. In addition to using a client-side SQL database this new version features:

These features mean that if you have add a bookmark to your homescreen for this app, you might as well be running a native app. It looks pretty native, stores data locally, doesn’t require a net connection and even features standard app UI mechanisms. The main giveaway is of course the chrome associated with the Safari browser. Still not bad for some html, css and javascript. Not a total replacement for native Cocoa apps, but it does put the creation of client-side apps for the iPhone into the hands of even more people.

If you are on an iPhone or are running Safari 4.0 you can try out jTODO yourself or watch the video of it in action below:

I won’t rehash the sql-side of things in this post – instead I’d refer you to my original post on the matter.

The use of iui was also fairly straightforward – I’m only using the style-sheets and images. This means that there are no animations involved, but at this stage it seemed excessive to add them in. Perhaps I’ll add some in a future version.

This leaves the offline application cache and getting drag and drop to work.

Offline application cache

The offline application cache is really simple to implement. It’s currently supported by Safari on the iPhone, Safari 4.0 and Firefox 3+.

In my case I want all files to be cached, so I simple specify them in a “manifest” file:


# version





This manifest file is then linked to the main html file thus:

<html manifest="todo.manifest">

That’s it. We now have an offline capable web-app. The main issue I had when doing this, was that Safari was very strict about the manifest – any file not mentioned in the manifest would not be loaded (even if it was normally accessible). The other issue of course is that we’ve now introduced another level of caching, so developing can be a bit annoying – as you think you’ve made a change, but then nothing shows up. I often ended up disabling the manifest for a while when debugging and then re-enabled it after things were working again. There’s also a version number in the manifest file, so that it well register as changed – to help refresh the caches after we’ve made a change.

With all this in place the app can be used when no net connection is available (e.g. in Airplane mode).

Drag and drop

The last job when developing this app was to enable drag and drop for re-ordering items. My first go at this worked pretty easily using jQuery UI’s sortable plugin – when running on my mac in Safari:

                axis: 'y',
                handle: '.handle',
                update: function(){
                    db.transaction(function(tx) {
                        $('.todo_item').each(function(i,item) {
                            var id = $(item).find(':input[type=checkbox]').attr('id');
                            id = Number(id.substring('todo_checkbox_'.length));
                            tx.executeSql('UPDATE todo SET todo_order=? WHERE id=?', [i, id]);

Essentially this is just setup to enabling drag and drop sorting only along the y axis (up and down), using the element with class handle to start the drag. Once the dragging has finished update gets called and I inspect the DOM to work out the current order of the todo_items and update the database accordingly.

That was pretty easy and working really well on the mac. Then of course I thought I’d test it on the iPhone. At that point I realised I’d forgotten that drag and drop doesn’t normally work in Safari in the iPhone. Holding and dragging normally scrolls the entire page – so drag and drop was a bit useless here.

However after a little digging I found someone had figured out how to get drag and drop working on the iPhone, by hijacking the various “touch” events that the phone generates. These work a little differently to the normal mouse events, but with some work can made to do our bidding:

    function handleTouchEvent(event) {
        /* from
         but changed a bit*/
        var touches = event.changedTouches;
        var first = touches[0];
        var type = '';
        // only want to do this for the drag handles
        if ( ! || ! ||"handle") == -1 ) {
        switch(event.type) {
            case 'touchstart':
                type = 'mousedown';
            case 'touchmove':
                type = 'mousemove';
            case 'touchend':
                type = 'mouseup';
        var simulatedEvent = document.createEvent('MouseEvent');
        simulatedEvent.initMouseEvent(type, true, true, window, 1, first.screenX, first.screenY, first.clientX, first.clientY, false, false, false, false, 0/*left*/, null);
        if ( event.type == 'touchmove' ) {
    document.addEventListener("touchstart", handleTouchEvent, false);
    document.addEventListener("touchmove", handleTouchEvent, false);
    document.addEventListener("touchend", handleTouchEvent, false);

This registers listeners for the touch events, but only does any extra work if the target of the event has the class “handle”. If that’s the case a simulated mouse event is sent for the first touched item. To stop the page from scrolling when we want to drag instead event.preventDefault() is called just for the touchmove event. This is sufficient to let jquery UI do it’s job and enable drag and drop sorting of the TODO items.

Django simple admin ImageField thumbnail

The Django admin site is one of the best features of Django. It really lets you just get on with building your app, without having to worry too much about how you’ll administer your site.

The defaults are generally pretty good, but it’s often the case that you’ll want to tweak and change it (particularly when you have clients involved). Luckily it’s pretty easy to customize.

One common change that many people will want to do is to display a thumbnail of an uploaded image in the admin. The default image field (when an image has been uploaded) in the admin looks like:


and we want to change it to look like this:


In my case I had images that I knew would be fairly small so I didn’t need to use any auto-resizing or anything like that. I found this snippet for doing the same task, but decided to simplify it a fair bit and ended up with:

from django.contrib.admin.widgets import AdminFileWidget
from django.utils.translation import ugettext as _
from django.utils.safestring import mark_safe

class AdminImageWidget(AdminFileWidget):
    def render(self, name, value, attrs=None):
        output = []
        if value and getattr(value, "url", None):
            image_url = value.url
            output.append(u' <a href="%s" target="_blank"><img src="%s" alt="%s" /></a> %s ' % \
                (image_url, image_url, file_name, _('Change:')))
        output.append(super(AdminFileWidget, self).render(name, value, attrs))
        return mark_safe(u''.join(output))

Then to use it I simply override formfield_for_dbfield to return a field that uses that widget for the field I’m interested in:

class MyAdmin(admin.ModelAdmin):
    def formfield_for_dbfield(self, db_field, **kwargs):
        if == 'profile_image':
            request = kwargs.pop("request", None)
            kwargs['widget'] = AdminImageWidget
            return db_field.formfield(**kwargs)
        return super(MyAdmin,self).formfield_for_dbfield(db_field, **kwargs)

It’s a fairly straightforward alteration to how the ImageField widget renders in the admin, but it is often a big help to be able to actually see the image in question.

UPDATED: Feb 24th, 2010. Based on Jeremy’s comment below and having upgraded to Django 1.1 I’ve modified this example to remove the “request” param from kwargs before passing it db_field.

Introducing NoteComb

I’ve been writing an application for my other half in recent months to help her organise observations of the children in her class. I’ve actually written two versions of the app. The first was dubbed “Observertron” and in retrospect was overly complex. After a bit of thought I was able to vastly simplify the app, whilst also making it more useful for other purposes beyond making observations.

The app is called NoteComb and is written in Python using wxPython. It’s essentially a specialised text-editor. The core feature is a grep-like search functionality coupled with the ability to edit text in-place during a search. Lines that don’t contain the search terms get hidden, leaving you free to edit the remaining lines as you want:

I’ve decided to take the time and try to package it up “properly”. So NoteComb is available as Mac and Windows apps, complete with icons etc. In fact to “regular” users it should appear that NoteComb is an app like any other – the fact it’s written using Python is largely incidental.

This packaging works pretty well overall and is pretty seamless once the app is downloaded, but it does tend to make for rather large apps. The Windows version when packaged as an installer runs in at about 4Mb, which isn’t too crazy, but the OS X app packed into a compressed DMG file weighs in at 15Mb! At the end of the day the app does include Python + wxPython + various libraries, so it’s not a surprise really, but I guess I was kind of hoping that I might develop in Python and get everything for free…

This is an early version of NoteComb (version 0.2.1), but it’s core functionality is there. Most of the extra work I’ve done has been on adding those little extra bits that aren’t core to the app, but are generally just expected (e.g. remembering previous window positions, copy/paste, undo/redo etc).

So feel free to download NoteComb and give it a go.