Friday, June 08, 2007

Steampunk LCD Monitor

To go with the steampunk keyboard and mouse, the guys over at steampunk workshop have made an absolutely amazing steampunk shell for and LCD-Flat panel.

You can see it being made here here.

Thursday, June 07, 2007

How to scan in 3d using milk, lego, and a webcam.

This instructable shows how to create 3d models using milk, lego and a webcam. I love low-tech solutions, and this ranks right up there.

This video shows how it works;

Monday, March 19, 2007

Sendfile Patch for Zope2

I've put together a patch for Zope that allows code to use the sendfile system call to transfer data out of Zope.

As this requires a file object, it's only available for use from trusted code, so that means inside a Product or an External method.

The good news is, that it's fairly easy to write an External method that does something useful like serve contents from a directory.

Here's an example external method that serves files from '/shared/images'

import os
directory = '/shared/images'

def Image(self, filename):
newPath = os.path.join(directory, filename)
if not os.access(newPath, os.F_OK|os.R_OK):
return ''
f = open(newPath, 'rb')
self.REQUEST.RESPONSE.sendfile(f, content_type='image/jpeg', other_headers = {'Content-Disposition', 'inline;filename=%s'%(filename))
return ''

It uses the sendfile wrapper module from here.

It gives you a speed up of 2-3 times serving content out of Zope from the filesystem.
I also have a patch for ExternalFile to let this use the sendfile patch.

You can get the code and the patch from

Saturday, February 24, 2007

Dick Cheney vs George Orwell

In an article in the Sydney Morning Herald titled Terrorists have ambitions of empire, says Cheney Dick Cheney is reported to have said;
[Terrorists' ultimate aim is to establish] "a caliphate covering a region from Spain, across North Africa, through the Middle East and South Asia, all the way to Indonesia -and it wouldn't stop there."

So this would mean we would see a map almost like this one (courtesty of wikipedia) where the yellow zone would indicate this caliphate;

The problem is, the yellow zones represent the site of the "Perpetual War" in George Orwell's 1984. In 1984 the perpetual war is unwinnable (and maybe fabricated), and is one of the mechanisms to to keep the population under control.

Amusing isn't it, that an Orwelling dystopia may be upon us?

Saturday, February 17, 2007

ZopeTrac Updated

I have updated ZopeTrac to 0.10.3, which makes it work with Trac 0.10.3.

You can get it from here; here.

I will try to mimic the Trac release numbers so you can tell what version of Trac it last worked with.

Tuesday, February 13, 2007

Some Advertisers are stupid...

Whilst doing a search on how to lodge a false advertising complaint, the following advertisement appeared. Perhaps these people need to be more selective in the terms they want to advertise with.


Monday, February 05, 2007

Set Windows Wallpaper from Python

*** For multiple monitors see this post instead Set windows wallpaper from python for multiple monitors  ***

Here's some code to set a random wallpaper from a list of images, or a list of directories or a single image. It doesn't recurse subdirectories, but, that's just as simple to add if you really require that functionality. It requires PIL.

You can set it to change the wallpaper to rotate to a new one at a specified number of minutes.

It can use any image that PIL can read (it converts it to a BMP).

# Code to rotate or set wallpaper under windows
# Copyright (C) Andrew K. Milton 2007
# Released under a 2-clause BSD License
# See:

import os
import time
import random

from optparse import OptionParser
from ConfigParser import SafeConfigParser
from ctypes import windll

from win32con import *
from PIL import Image

I recommend you create a pywallpaper.conf file that looks something like this;
paths = C:\Documents and Settings\akm\My Documents\My Pictures\gb
C:\Documents and Settings\akm\My Documents\My Pictures\Ralph

to store the directories in rather than specifying -d multiple times on the command line"""

def getDefaultDirs():
return [r'C:\Documents and Settings\All Users\Documents\My Pictures\Sample Pictures',]

def setWallPaperFromBmp(pathToBmp):
""" Given a path to a bmp, set it as the wallpaper """
result = windll.user32.SystemParametersInfoA(SPI_SETDESKWALLPAPER, 0,
if not result:
raise Exception("Unable to set wallpaper.")

def setWallPaper(pathToImage):
""" Given a path to an image, convert it to bmp format and set it as the wallpaper"""

bmpImage =
newPath = os.getcwd()
newPath = os.path.join(newPath, 'pywallpaper.bmp'), "BMP")

def setWallPaperFromFileList(pathToDir):
""" Given a directory choose an image from it and set it as a wallpaper """
# Image directories often contain Thumbs.db or other non-image
# files or directories, try a few times to set a wallpaper, and then just give up.

tries = 0
done = False

while (not done) and tries < 3:
files = os.listdir(pathToDir)
image = random.choice(files)
setWallPaper(os.path.join(pathToDir, image))
done = True
tries += 1
return done

def setWallPaperFromDirList(pathList):
""" Given a list of directories choose a directory """
imageDir = random.choice(pathList)
status = setWallPaperFromFileList(imageDir)

# Don't really need to say anything if we couldn't set the
# wallpaper, I think the user will notice

def getImageDirectories(options):
configFile = 'pywallpaper.conf'

if options.configFile:
configFile = options.configFile

dirs = options.directories

config = SafeConfigParser()
dirs += config.get('directories', 'paths').split('\n')

if not dirs:
# raise Exception("No directories defined")
dirs = getDefaultDirs()
return dirs

def setWallPaperFromConfigDirs(options):

def getCommandLineOptions():
parser = OptionParser()
parser.add_option("-t", "--time", dest="change_time",
help = "Change wallpaper time in minutes (0 = change once and exit [default])",
default = 0, type = "int")
parser.add_option("-i", "--image", dest="singleImage", default = None,
help = "Set wallpaper to this image and exit (overrides -d)")

parser.add_option("-d", "--directory", dest="directories", default = [],
action="append", type="string",
help = "Add an image directory")

parser.add_option("-c", "--config", dest="configFile", default = None,
help = "path to alternate config file (default <working dir>/pywallpaper.conf)")

parser.add_option("-w", "--workingdir", dest="cwd", default=".",
help = "Working Directory (default .)")

(options, args) = parser.parse_args()
return (options, args)

if __name__ == '__main__':

options, args = getCommandLineOptions()

if options.cwd and options.cwd != '.':

if options.singleImage:
elif not options.change_time:
dirs = getImageDirectories(options)
sleepTime = options.change_time * 60.0
while True: