Saturday, March 06, 2010
Fallout 3 -- Crash Fixed
It failed once before and it turned out to be an nVidia video driver update, and a new update fixed it. However it's been over 6 months now and multiple nVidia updates have failed to fix it.
I spent some time this weekend debugging it, and discovered it's some kind of issue with Fallout 3 and DisplayLink drivers. I had tried unplugging my Mimo 7" USB auxillary monitor before, and Fallout 3 had still crashed. It turns out, that it was still crashing inside Fallout 3 when it returned from the DisplayLink drivers. I assume there's some monitor iteration or some other call going on, and it's not happy when something comes back with bounds smaller than the main screen.
Anyhow, if you have issues with Fallout 3 and you have "other" video/monitor drivers, try uninstalling them.
Iterative Collatz in Python (with resume)
Here's a non-recursing version that will resume when you restart it.
Given all numbers to 2^58 have already been checked you might be there a while...
It's trivial to get it to dump a CSV with the steps for graphing, but, this one doesn't do that (but gives you the steps so that you can).
If you don't know what this is for, it doesn't matter.. (but you can google it...)
import os def collatz(n): steps = [] stAppend = steps.append while n > 1: stAppend(n) while not (n & 0x1): n >>= 1 stAppend(n) if n == 1: break n = n * 3 + 1 return steps if __name__ == '__main__': n = 2 if os.access('collatz.prg', os.F_OK|os.R_OK|os.W_OK): n = int(open('collatz.prg', 'rb').read()) while True: steps = collatz(n) open('collatz.prg', 'wb').write(str(n)) print n, len(steps) n += 1
Friday, February 26, 2010
Adding a "submit on enter" in ExtJS formpanels.
Googling only turned up some fairly unappetizing solutions.
Here's a way using defaults. Just change the getCmp or parametize it if you want, I've left it as a constant for illustration purposes.
Add this to your FormPanel constructor and all your fields will get "submit-on-enter".
If you only want 1 field to have it then just add everything inside the defaults to that 1 field.
defaults:{ enableKeyEvents:true, listeners:{ specialKey: function(field, el) { if(el.getKey() == Ext.EventObject.ENTER) { Ext.getCmp('address-search-button').fireEvent('click'); } } } }
Saturday, February 20, 2010
Decode Encrypted CueCat Output With Ugly Python
import sys; from string import maketrans as m; from binascii import a2b_uu as d q = lambda x,y: ''.join([chr(c) for c in range(ord(x), ord(y) + 1)]) t = m(q('a','z') + q('A','Z') + q('0','9') + '+-', q(' ','_')) def u(st): return ''.join([chr(ord(c) ^ 67) for c in d(chr(32 + 3 * len(st) / 4) + st)]) print "ID: %s, Type: %s, Barcode: %s"%(tuple([u(b.translate(t)) for b in sys.stdin.read().split('.')[1:-1]]))
Saturday, February 13, 2010
12 Bar Blues on an Arduino
Using a small 8ohm analogue speaker hooked up to pin 11, by strobing the pin, I generate a square wave (a kind of annoying timbre to be honest).
I generate 2 octaves of semitones starting with A-220 and index into it.
The timing is currently inaccurate as the note length for lower notes runs slightly longer (half a pulse width) than higher notes due to how the strobing currently works. It's surprisingly noticeable. I need to work on that to make it more consistent. Probably by using timer interrupts instead of delays.
To do:
Alter the volume by using analogWrite() to set the duty cycle of the pin... 255 = loud 0 = off.
I think I can use that mechanism to generate other waveforms, I'll probably try sawtooth next.
Proper ADSR waveforms.
Multichannel output (haw haw).
const int baseFreq = 220; // A const int numHalfTones = 24; // 2 Octaves long frequencies[numHalfTones]; long halfFreqs[numHalfTones]; /* 12 semi-tones per octave | Bf| | | C#| Ef| | |F# |G# | -+---+ | +---+---+ | +---+---+- | A | B | C | D | E | F | G | A | +---+---+---+---+---+---+---+---+ 2 octaves: 0 1 2 3 4 5 6 7 8 9 10 11 A Bf B C C# D Ef E F F# G G# 12 13 14 15 16 17 18 19 20 21 22 23 */ int seq[] = { 3, 7, 10, 12, 13, 12, 10 , 7, 3, 7, 10, 12, 13, 12, 10 , 7, 8, 12, 15, 17, 18, 17, 15, 12, 3, 7, 10, 12, 13, 12, 10 , 7, 10, 14, 17, -1, 8, 12, 15, -1 }; int notes = 40; long getTimeHigh(int i) { return halfFreqs[i]; }; void ToneGen(void) { float baseMult; int i; int lastTone = baseFreq; baseMult = pow(2.0 , 0.083333); for(i = 0; i < numHalfTones; ++i) { long frequency = baseFreq; if(i) { frequency = (0.5 + (frequencies[i - 1] * baseMult)); } frequencies[i] = frequency; halfFreqs[i] = (0.5 + (1000000.0 / frequency / 2.0)); } }; void setup(void) { pinMode(11, OUTPUT); ToneGen(); Serial.begin(57600); } int rest_count = 100; long duration = (60 * 1000000) / 288; void playNote(int idx) { long tone = 0; if (idx >= 0) { tone = getTimeHigh(idx); } long endTime = micros() + duration ; if (tone > 0) { int val = HIGH; while (micros() < endTime) { digitalWrite(11,val); delayMicroseconds(tone); val = !val; } } else { delay(duration / 1000); } digitalWrite(11, LOW); } void loop(void) { analogWrite(11, 0); for(int i = 0; i < notes; ++i) { playNote(seq[i]); delay(10); } }
Friday, June 08, 2007
Steampunk LCD Monitor
You can see it being made here here.
Thursday, June 07, 2007
How to scan in 3d using milk, lego, and a webcam.
This video shows how it works;
Monday, March 19, 2007
Sendfile Patch for Zope2
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'
It uses the sendfile wrapper module from here.
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):
self.REQUEST.RESPONSE.setStatus(404)
return ''
f = open(newPath, 'rb')
self.REQUEST.RESPONSE.sendfile(f, content_type='image/jpeg', other_headers = {'Content-Disposition', 'inline;filename=%s'%(filename))
f.close()
return ''
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 zope.org
Saturday, February 24, 2007
Dick Cheney vs George Orwell
[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
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...

Dumb.
Monday, February 05, 2007
Set Windows Wallpaper from Python
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: http://www.opensource.org/licenses/bsd-license.php 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; [directories] 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, pathToBmp, SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE) 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 = Image.open(pathToImage) newPath = os.getcwd() newPath = os.path.join(newPath, 'pywallpaper.bmp') bmpImage.save(newPath, "BMP") setWallPaperFromBmp(newPath) 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: try: files = os.listdir(pathToDir) image = random.choice(files) setWallPaper(os.path.join(pathToDir, image)) done = True except: 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 try: config = SafeConfigParser() config.readfp(open(configFile)) dirs += config.get('directories', 'paths').split('\n') except: pass if not dirs: # raise Exception("No directories defined") dirs = getDefaultDirs() return dirs def setWallPaperFromConfigDirs(options): setWallPaperFromDirList(getImageDirectories(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 != '.': os.cwd(cwd) if options.singleImage: setWallPaper(options.singleImage) elif not options.change_time: setWallPaperFromConfigDirs(options) else: dirs = getImageDirectories(options) sleepTime = options.change_time * 60.0 while True: setWallPaperFromDirList(dirs) time.sleep(sleepTime)
Thursday, October 12, 2006
The more things change, the more they stay the same.
-- W.B. YeatsThings fall apart; the center cannot hold;
Mere anarchy is loosed upon the world,
The blood dimm'd tide is loosed, and everywhere
The ceremony of innocence is drowned;
The best lack all conviction, while the worst
Are full of passionate intensity.
Friday, May 12, 2006
Zope and Trac
It seems to work fine (at least for me).
You can find it here
Friday, May 05, 2006
Erin and Scott's Web Blog: Engagement ring shopping
Fads & Erin got engaged! OMG jas and I are so stoked for them.
We both think Fads' heart probably nearly failed when he asked.
Thursday, April 13, 2006
Australian Eastern Timezones in Zope
The problem is that Zope thinks that the EST and EDT timezones should be AEST and AEDT, well that's not what they're called, so most of the AU Zope servers run in US/Eastern time, which is very very very annoying.
So if you're in an Eastern AU state and you'd like your logs and times to be local without jumping through hoops, try downloading; ZAUTZ
Monday, April 03, 2006
More uploader stuff
So you can use the wysiwyg editor, and add images from your HDD as you go.
I'll probably end up posting to the zope list for help with the IE javascript issues, since noone has responded on IRC or to the blog entry.
Saturday, April 01, 2006
Async AJAX Uploader with progress bar for Zope

Async Upload Demo in Action
I'll release this code soon, I've got to find some people to alpha test it, I'm sure I'll have a few volunteers.
Actually if you know a bit about JavaScript for IE, I'd be happy for you to contact me as some of the status updating code doesn't work so well for IE (runs like a charm in FireFox), so I can get an IE version of it working. The JS code itself does fairly simple things, but, doesn't work satisfactorily in IE.
No, it's not an April Fool's joke.
Monday, March 27, 2006
More side projects, and (small) Javascript grid rant.
Meanwhile I'm working on Javascript parser in python. I'm not sure where this will end up, but, I can see that it would be very useful to be able to run javascript inside python.
I've been trying to find a 'nice' looking template so I can actually build a 'proper' website. I've spent a few hours playing around building static pages, and I just can't be bothered. So I guess I'll being doing something in Zope for that too. Actually once I get that up and running, I think I might consolidate all of my various projects there. As always it's finding the time, and since we're being evicted, I don't think I'll make any headway on that until after we find a new place and move in.
I played a little with jsolait and Zope the other day. The jsolait xmlrpc lib is like python's so it's nice to use (even though I'm not a Javascript guy really), but, it's going to help out on my current paying gig, so it was worth investigating. I'm not really a front-end guy at all, but, it's irritating that even the 'nice' javascript grid widgets suck. I guess that's a byproduct of living inside a webpage. I really want to be able to create a grid that grows and shrinks dynamically. All of the ones I've seen so far, can grow, but, never get any smaller. That's great if you want to browse a fixed dataset, but, rotten if, for example, you want to display an active queue of items.
On the grid thing, the LiveGrid people suggested we no longer needed paging, and we could just use scrolling to navigate through datasets. Well that's great if your dataset is really small, but, it's sucks if you want to get to something in the middle of the dataset. Something that will stay in the middle of the dataset regardless of how you sort it. I often find myself binary searching results from various searches trying to find the set I want (I'm not talking google searches here). I don't want to go back to linear search.
Sunday, March 19, 2006
Speeding up ZPTs
I''ve written my own TAL engine, and I was testing it to see if it was any faster;
Using this template (thanks mcdonc d8), I ran a test using the venerable ab tool that comes with apache. Don't write in to tell me my hardware is crap, I know that, I don't performance test on high-performance hardware..
<html xmlns:tal="http://xml.zope.org/namespaces/tal">
<head>
<title>This is the title</title>
<div>This is the head slot</div>
</head>
<body tal:define="values python:[('bug', 'me'),]*20">
<div>
<span tal:replace="values" />
<form action="." method="POST">
<table border="0">
<tbody>
<tr tal:repeat="itemz values" class="foo">
<td tal:content="python: itemz[0]">Name</td>
<td tal:content="python: itemz[1]">Description</td>
</tr>
</tbody>
</table>
</form>
</div>
</body>
</html>
The following are directly to Zope, not via apache.
First standard Page Templates;
And now my Templates.
Server Software: Zope/(Zope
Server Hostname: xanadu
Server Port: 8080
Document Path: /tmp/testTemplate2
Document Length: 2444 bytes
Concurrency Level: 10
Time taken for tests: 9.467635 seconds
Complete requests: 1000
Failed requests: 0
Write errors: 0
Total transferred: 2651000 bytes
HTML transferred: 2444000 bytes
Requests per second: 105.62 [#/sec] (mean)
Time per request: 94.676 [ms] (mean)
Time per request: 9.468 [ms] (mean, across all concurrent requests)
Transfer rate: 273.35 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.8 0 9
Processing: 20 93 13.1 93 189
Waiting: 18 87 12.5 88 169
Total: 20 93 13.2 93 189
Percentage of the requests served within a certain time (ms)
50% 93
66% 94
75% 94
80% 94
90% 99
95% 105
98% 143
99% 150
100% 189 (longest request)
Server Software: Zope/(Zope
Server Hostname: xanadu
Server Port: 8080
Document Path: /tmp/testTemplate
Document Length: 2262 bytes
Concurrency Level: 10
Time taken for tests: 7.341181 seconds
Complete requests: 1000
Failed requests: 0
Write errors: 0
Total transferred: 2469000 bytes
HTML transferred: 2262000 bytes
Requests per second: 136.22 [#/sec] (mean)
Time per request: 73.412 [ms] (mean)
Time per request: 7.341 [ms] (mean, across all concurrent requests)
Transfer rate: 328.42 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.8 0 9
Processing: 23 72 13.6 72 170
Waiting: 21 66 12.7 67 130
Total: 23 72 13.6 72 170
Percentage of the requests served within a certain time (ms)
50% 72
66% 73
75% 73
80% 74
90% 87
95% 94
98% 107
99% 115
100% 170 (longest request)
30% faster, and that's a trivial page template. I need to find a less synthetic test, to do some 'real' testing and find out how much faster it really is, especially with METAL involved.
I can speed it up a little more too by sharing the 'cooking' between threads.
Anyhow stay tuned...