Saturday, May 23, 2009

Surprise in math.h

Quick Quiz: What does the following code output:

#include <math.h>
#include <stdint.h>
#include <stdio.h>

int main(int argc, char **argv)
{
    int i = INT32_MIN;
    printf("i is: %d\n", i);
    printf("abs(i) is: %d\n", abs(i));
}

Select the following to see the result...

stephen@frank:/tmp$ gcc test.c -o test
stephen@frank:/tmp$ ./test 
i is: -2147483648
abs(i) is: -2147483648

Woah! This comes from the 2s complement representation of INT32_MIN. It's 1 followed by all zeros. When abs() does the standard invert-all-bits-then-add-one technique for turning a negative into a positive it turns INT32_MIN into... INT32_MIN!

Thanks to http://www.youtube.com/watch?v=wDN_EYUvUq0

Monday, May 4, 2009

Importing Python packages in-memory

Student Robotics needs to import python packages written by the students into a simulator. Currently the simulator downloads a ZIP of the python package to the temp directory, then uses the inherent ability of python to transparently treat a zip file as a package to import the code. This has caused us problems, mainly as some schools don't allow students to write to %TEMP%!!!

We are now planning to run the simulator as a web service - Students will save their code in an online IDE and then request a simulation to be run. A physics engine will be plugged in, and some nifty Javascript used to draw a little virtual robot driving around a virtual arena. This means that we (Student Robotics) are running untrusted code on our servers by design. In order to carefully manage our sanity we will be running the students code in its own process as a severely crippled user. This includes banning writing to disk.

We can't use the standard python zip imports as the zipfile module only supports opening files directly off disk. I have implemented some import hooks to add the ability to import files from a zip file held in memory. Exceptions aren't handled, that's up to the caller.

EDIT: Compile before exec so I can set the filename of the code object correctly.

import zipfile, StringIO, imp, sys, os.path

f = StringIO.StringIO()
f.write(open("robot.zip", "rb").read())

zip = zipfile.ZipFile(f)

modules = dict([(os.path.splitext(z.filename)[0], zip.open(z.filename).read())
                    for z in zip. infolist() \
                    if os.path.splitext(z.filename)[1] == ".py"])

class Loader:
    def __init__(self, fullname, contents):
        self.fullname = fullname
        self.contents = contents

    def load_module(self, fullname):
        if fullname in sys.modules:
            return sys.modules[fullname]

        mod = sys.modules.setdefault(fullname, imp.new_module(fullname))
        mod.__file__ = "<%s>" % fullname
        mod.__loader__ = self

        code = compile(self.contents, mod.__file__, "exec")

        exec code in mod.__dict__
        return mod

class Finder:
    def __init__(self, modules):
        self.modules = modules

    def find_module(self, fullname, path=None):
        if (fullname in self.modules) and (path == None):
            return Loader(fullname, self.modules[fullname])

        return None

sys.meta_path.append(Finder(modules))

def trace(frame, event, arg):
    if event == "call":
        print frame.f_code.co_filename
    return None

sys.settrace(trace)

print "**************************"

import robot

f = robot.Face()
f.cheese()
f.bee()

Monday, March 30, 2009

Private Tutor


Private Tutor, originally uploaded by StephenEnglish.

If you're looking for a private tutor in Melbourn, Cambridgeshire then get in touch!

Tuesday, February 10, 2009

pidgin-countdown

I head off skiing in 10 days, 8 hours 57 minutes and 59 seconds. No, now 10 days, 8 hours 57 minutes and 54 seconds. No, wait, 10 days, 8 hours 57 minutes and 49 seconds. Well, you get the idea. I'm pretty excited - so I blew a couple of hours writing my first Pidgin plugin - Pidgin-Countdown.

Pidgin-Countdown sets your MSN/Google Chat/Whatever status counting down to a specific point in time, updated at a configurable interval.

Tuesday, November 25, 2008

Default media file extensions in Gnome

Just got my shiny new G1 and tried to copy music onto it with Rhythmbox. To do this you need to:

  1. Create a .is_audio_player file on the device. I followed the Banshee specs - here's mine:
    audio_folders=Music/
    folder_depth=2
    output_formats=application/ogg
  2. Copy music across!

Unfortunately this didn't quite work. A little fiddling later I realised that by default my system creates ogg files that are have the extension "oga", and my G1 doesn't recognise this as an audio file. After some 20 minutes of diving through the Rhythmbox source code, drilling down through the nest of library calls I found that the extension is supplied by the system schemas installed with the gnome-media-common package. A little more digging later I found that this extension can be tweaked using gconf-editor - success!

Monday, November 17, 2008

IDEs are for Wimps

stephen@frank:~$ gcc -x c - << 'EOF'
> #include 
> 
> int main(int argc, char **argv)
> {
> printf("Hello World!\n");
> return 0;
> }
> EOF

Sunday, October 19, 2008

Greasing the Monkey

Just wrote my first Greasemonkey script to help out an old friend. The script (http://userscripts.org/scripts/show/35685) adds links to BBC Radio schedules (e.g. http://www.bbc.co.uk/radio7/programmes/schedules) where you can download the Realplayer version of a show that's on IPlayer. I was quite impressed by how easy putting together a Greasemonkey script was. Unfortunately there seems to be a limit to how many GM_xmlhttpRequest functions you can fire off (seems to be about 5). As I need to hit a second page to find each RealPlayer link, this limit means I can't get the links for all shows on a schedule when the page loads.