Still Watching This Space?
Aug. 23rd, 2007 | 06:33 pm
If you're still subscribed to this blog, you are missing out on one of the most important tech blogs to come out of Tasmania.
Update your feeds to http://mumak.net.
However, if you happen to use livejournal.com as your RSS aggregator, then you may be interested in http://jonathanlange.livejournal.com. It's an LJ-syndicated version of mumak.net, graciously provided by Mary.
jml
Link | Leave a comment {1} | Add to Memories | Tell a Friend
Blog Moved Permanently
Aug. 4th, 2007 | 01:24 pm
I am now going to blog from mumak.net. Please update your RSS feeds.
I'll try to get a syndication going for LJ addicts.
jml
Link | Leave a comment {2} | Add to Memories | Tell a Friend
Headlines
Mar. 13th, 2007 | 10:02 am
- Reading Confessions. Enjoying it.
- Bought a Macbook. Running Feisty. More info later.
- Missing iCal terribly.
- Was ill over the Eight Hours Day long weekend.
- Tasmania's bus system doesn't cater to weekend tourism.
- Just watched all of Season 1 of 24. I love how every second sentence ends with "now!".
- Looking to pay people to host mail for myself and Crossroads (several mailing lists and addresses).
- Finished every single level on Super Mario World except the final battle with Bowser.
- Everyone at Crossroads loves WarioWare Smooth Moves. Unfortunately, someone filmed me doing the dance routine from the Tiny Wario section.
- Not contributing much to Twisted at the moment.
- There is a testing-in-python mailing list. There is some interesting discussion going on there. I just hope that the people there who are writing things learn from xUnit, Trial, nose and bzr.tests and don't just make the assumption that not having to write a 'class FooTest(TestCase):' statement makes something cool.
- On testing, glyph has promised to finally tell me what he means about xUnit.
Link | Leave a comment {3} | Add to Memories | Tell a Friend
EIGHT HUNDRED AND FIFTY DOLLARS
Feb. 12th, 2007 | 03:20 pm
Currently, the Macbook is the front-runner, especially now that I have a canary to descend into the mines and check whether it will run Linux properly.
Still, the Thinkpad X60 looks like a fine machine. If only it didn't cost 3,599 AUD to buy one. If only I could find some magical wonderland where hardware is a cheap as chips.
As it turns out, this magical wonderland actually exists.
Come with me to New Zealand!
Cross the ethereal Tasman and go to Lenovo's New Zealand website. Gaze upon their X Series range. Gasp in amazement at the price of the 2GHz X60—3,129 NZD. That's about 2750 AUD. Or, as like I to say it:
EIGHT HUNDRED AND FIFTY DOLLARS LESS.
I called Lenovo's Australian sales centre and asked them about the price difference. They pointed out that the New Zealand price doesn't include Australia's 10% GST. However, even with GST, it's still about 575 AUD cheaper in New Zealand. They pointed out that Lenovo Australia is offering a free MP3 player worth over $200 for free with the X60 laptops. They speculated that demand for the Thinkpad X60 might be higher here in Australia. They sounded unconvinced.
Wild plans have been buzzing around my head. Perhaps I could fly to New Zealand and bought a laptop there. No, the tickets alone would cost between $700 and $850. I could arrange for a friend in New Zealand to order the laptop and then ship it over. Still, that's a lot of hassle. Perhaps it's worth it.
The information is out there, let the market forces do their work!
Link | Leave a comment | Add to Memories | Tell a Friend
"Linux" Annoyances
Feb. 5th, 2007 | 06:10 pm
- Lack of a keyboard-driven way to launch applications or switch between open windows by name. That is, lack of Quicksilver.
- No convenient way to cycle between open windows of an application. The equivalent OS X operation is Cmd-`. I suspect this is why many linux apps have sprouted tabs.
- New windows steal focus. I've talked about this a little on IRC. If you launch an application from the menu, then switch to IRC to type something witty, the new application's window might appear and steal your focus mid-witticism. Very irritating.
I'd say more about applications, windows, switching and launching and how some of them are the same and others are different, but I'm really, really hungry.
Punters, let me know what I can constructively do about my Linux annoyances.
Link | Leave a comment {6} | Add to Memories | Tell a Friend
Let's Go Shopping
Feb. 3rd, 2007 | 05:53 pm
My new laptop has to be able to run Linux. In particular, the built-in wifi needs to work. I won't mind it if I'm forced to spend some time doing non-custom config, as long as it will work.
I'm going to have to travel a bit more than usual, so I want my new laptop to be smaller and preferably lighter than my 15" Powerbook... and I want good battery life too.
Now, looking around, the best value-for-money laptop appears to be the Macbook. If you take a similarly sized Dell and add features to it until you have a Macbook equivalent, then you'll end up paying more money.
I'm still not set on getting a Macbook -- I'm a little scared about Linux support.
What advice do you have for me, O reader?
Update: Someone recommended a Lifebook. More expensive, but all its innards are Intel, which makes for Linux goodness.
Update: People have asked me for figures. A
2.0GHz Macbook with 1GB RAM and 120GB HDD costs AUD 2399. A similarly specced ThinkPad T60 costs AUD 3699. The ThinkPad X60 1706H7M costs AUD 3599. The Lifebook S6311 costs AUD 2999.
Link | Leave a comment {5} | Add to Memories | Tell a Friend
Good Morning Freedom Lovers!
Jan. 29th, 2007 | 05:48 pm
Two crazy ideas I had while in Sydney. I'm posting them here because I think they are worth discussing and there's pretty much no other way I can act on them.
1. A Google Maps-style app which showed real estate / rental prices as contours / altitudes / colour.
2. A OLPC application designed to let children make up their own games with their own rules and play those games with other OLPC-laptop owners. No clue how to do this.
What do you think?
Link | Leave a comment {7} | Add to Memories | Tell a Friend
LOL
Nov. 28th, 2006 | 11:31 am
"""
"""
Well said, sir!
Link | Leave a comment {1} | Add to Memories | Tell a Friend
Thanks
Nov. 23rd, 2006 | 10:18 am
Even though Australians don't celebrate Thanksgiving, I thought I'd get into the spirit of the season by giving my thanks to the various free and open source software projects that I use every day.
- Firefox
- I know you guys get a lot of flack and you need to sort out your crazy, crazy licensing, but I still love you anyway. Thank you for DOM Inspector.
- Firebug
- Thank you. Thank you. Thank you.
- Emacs
- We've been together for years. Even though I've used other editors, you've always been there for me, patiently waiting and improving.
- X-Chat Aqua
- Even though I'm stranded in OS X, it still doesn't mean I can't pretend.
- Adium X
- I can't tell you how much I appreciate being able to have exactly one IM client. Merging contacts is such a good idea.
- Trac
- Definitely not perfect, but who is? When you are actually up and running, you are reasonably effective at tracking bugs, and I'm thankful for that. Wiki markup in commit messages and ticket comments is an excellent idea.
- Python
- Namespaces are one honking great idea -- let's do more of those!
- Twisted
- I've learnt so much from working on Twisted. Once you get past the weirdness and the brash exterior, the community has a heart of gold. I'm glad to be a member.
- The rest
Those are the applications and libraries I actually, regularly use. However, most of them owe their existence and vigour to a host of libraries and tools. Thanks to gcc, libgaim, openssl, pyopenssl, gtk, the python standard library, expat, ssh, screen, vim and on and on and on.
The foundations are so vast, it is hard to imagine so many programmers giving so much time. Spending hundreds of hours chasing down bugs, reading specs, writing tests, composing arguments for mailing lists, packaging, implementing UI edge cases, triaging bugs and occasionally actually writing code that does stuff.
Thanks to the men and women of the FOSS community.
Link | Leave a comment | Add to Memories | Tell a Friend
There and Back Again
Nov. 18th, 2006 | 11:54 pm
So I backed up my OS X install (using the very nice Super Duper) and took the plunge. I had a plan. It had a lot of steps.
Step 1, install the OS. No problems here.
Step 2, set up wifi. Uh oh.
There are some very clear and simple instructions on how to get Ubuntu talking to the nasty, proprietary little wifi card inside the powerbook (thanks nickm!). I followed these, and was able to scan for networks. Alas, I wasn't able to actually connect to any of them.
It appears that other people have had this problem. Unfortunately, hours of search left me without solution or diagnosis. No one has replied to my forum post. The people on #ubuntu got me to try all the obvious things (I'd already tried them), and the people on #ubuntu-au did much the same, except they were more friendly and had longer attention spans. The aussies also gave me a lead -- apparently cafuego has bundled some firmware and I should try that.
Unfortunately, by the time I got that lead, I had already begun to restore my OS X installation to its natural home.
I'm a little disappointed about the whole experience. Apart from taking up a slab of free time that I could have spent on other things,
it means I still lack a Linux workstation...
... which could be embarrassing when I'm at LCA 2007. I've registered and booked my tickets. I'm not sure if I've paid yet. They wouldn't let me pay when I registered. Hmmm. I should talk to someone about that.
Anyway, it's my intention to be in Sydney for LCA 2007. I hope to see you there, dear reader.
Link | Leave a comment {4} | Add to Memories | Tell a Friend
Cargo Pants of Escape
Oct. 7th, 2006 | 11:33 pm
Can anyone recommend a new phone? (Also, yes, I lost everyone's number again. Please get in touch).
Link | Leave a comment | Add to Memories | Tell a Friend
Axiom Powerups Summarised
Sep. 13th, 2006 | 02:04 pm
Thanks to idnar for this.
- Item is a subclass of Empowered, which has powerUp() and powerDown()
- You pass in another item (the "powerup") and an interface
- You can call item.powerupsFor(interface) and item.interfacesFor(powerup)
- Once you've done foo.powerUp(bar, IFoo), IFoo(foo) will give you bar
- If foo has many powerups implementing IFoo, IFoo(foo) gives you the first one returned (ordered by priority)
- However, you generally want either all IFoo powerups, or you don't want to have more than one IFoo powerup installed in the first place.
For more information, see the Axiom website.
Link | Leave a comment | Add to Memories | Tell a Friend
Making the Switch
Jul. 25th, 2006 | 02:10 pm
Last time I tried this (pre Dapper release), I had lots and lots of trouble with getting Caps Lock to behave as a control, and with getting my wireless card to work. Has this been fixed?
Any other advice?
Link | Leave a comment {1} | Add to Memories | Tell a Friend
How to Disconnect in Twisted, Really
Jul. 7th, 2006 | 06:51 pm
Trial is about to become a fair bit stricter on tests that don't clean up after themselves. In particular, any test that doesn't properly close all of its connections is going to fail ugly. Lots of Twisted's tests fail very ugly.
If you are already glazing over with apathy towards unit tests, unglaze now. Disconnecting is a little more involved than you might expect, and there's every chance you aren't doing it correctly.
Thanks to moshez and teratorn for reviewing this document. Any errors are still my fault.
How to Disconnect in Twisted, Really
You are writing a test for some network code. You have already written many unit tests for the protocol and the protocol factories, and you assume that the lower level socket calls all work. You have deep confidence in your code, but you need more.
You yearn to write an end-to-end test. To set up the server, have it really listen, have the client really connect. You want data to zoom back and forth over the wire like luxury sportscars on the Autobahn.
Fine.
You start with a server and a client.
You want the client to connect to the server. You want things to happen. When things have happened, you want to assert stuff.
After the assertions, you want to disconnect the client and you want the server to go away.
Good.
I'm not going to help you set things up, I'm not going to help you make things happen. I am going to help you make all your connections just go away.
Let me lay down the law:
- The server must stop listening.
- The client connection must disconnect.
- The server connection must disconnect.
You have to make each of these things happen. That's easy. Here's the tricky part: you have to wait for each of these things to happen.
To make the server stop listening:
port = reactor.listenTCP(portNumber, factory)
...
port.stopListening()
You can effect the last two with one stroke, using either of the following
commands:
protocol.transport.loseConnection()
OR
connector = reactor.connectTCP(host, port, factory)
...
connector.disconnect()
Now, just running these commands is not enough. Twisted is asynchronous: you have to wait for it to call you.
The way to wait for something in a Trial test is to return a Deferred from
the test method.
stopListening is easy. It returns a Deferred if it is going to take a
while. The others are harder. There is only one way to know when the connection
has truly been lost: override connectionLost on a Protocol instance. Pass
a Deferred to your Protocol and have connectionLost call callback on
that Deferred. You will need to do this for both the client and the
server protocols. Once you have your three Deferreds, return them in a
DeferredList.
Simple.
UPDATE: exarkun tells me that there are two ways to know when the connection has truly been lost on the client side. ClientFactory.clientConnectionLost is the other one.
Summary
In order to clean up a test that connects a client to a server, you need to
wait on three Deferreds: one for the listening port, one for the server
protocol and one for the client protocol.
Below is an example demonstrating how to disconnect. As you can see, it is quite verbose. Trial does not provide any shortcuts, even though it should.
from twisted.internet import defer, protocol
from twisted.trial import unittest
class ServerProtocol(protocol.Protocol):
def connectionLost(self, *a):
self.factory.onConnectionLost.callback(self)
class ClientProtocol(protocol.Protocol):
def connectionMade(self):
self.factory.onConnectionMade.callback(self)
def connectionLost(self, *a):
self.factory.onConnectionLost.callback(self)
class TestDisconnect(unittest.TestCase):
def setUp(self):
self.serverDisconnected = defer.Deferred()
self.serverPort = self._listenServer(self.serverDisconnected)
connected = defer.Deferred()
self.clientDisconnected = defer.Deferred()
self.clientConnection = self._connectClient(connected,
self.clientDisconnected)
return connected
def _listenServer(self, d):
from twisted.internet import reactor
f = protocol.Factory()
f.onConnectionLost = d
f.protocol = ServerProtocol
return reactor.listenTCP(0, f)
def _connectClient(self, d1, d2):
from twisted.internet import reactor
factory = protocol.ClientFactory()
factory.protocol = ClientProtocol
factory.onConnectionMade = d1
factory.onConnectionLost = d2
return reactor.connectTCP('localhost',
self.serverPort.getHost().port,
factory)
def tearDown(self):
d = defer.maybeDeferred(self.serverPort.stopListening)
self.clientConnection.disconnect()
return defer.gatherResults([d,
self.clientDisconnected,
self.serverDisconnected])
def test_disconnect(self):
pass
Link | Leave a comment {11} | Add to Memories | Tell a Friend
Windows
Jul. 5th, 2006 | 12:24 pm
- Get Firefox
- Get PuTTY
- Shell into a unix machine, launch screen, launch irssi
- Configure a Twisted development environment
- bzr
- Make Caps Lock an additional Control
- A decent terminal. (Maybe Terminator. Has anyone tried it?)
Update: I have already been asked to reboot my computer. Ahh, the memories.
Link | Leave a comment | Add to Memories | Tell a Friend
Phone Lost, Number Found
Jun. 20th, 2006 | 12:21 pm
Link | Leave a comment | Add to Memories | Tell a Friend
Lost Phone
Jun. 16th, 2006 | 10:25 am
If you have it, and by some miracle find this post, please return it.
Link | Leave a comment {3} | Add to Memories | Tell a Friend
Emacs Tricks
May. 26th, 2006 | 11:32 am
It works, and means the painful indentation problems that I talked about earlier just go away.
Link | Leave a comment | Add to Memories | Tell a Friend
Test Driven Development with Athena
May. 24th, 2006 | 02:15 pm
This post is for people like me who have forgotten how to program without writing unit tests first. Kent Beck's book shows why this is good state to be in.
The Divmod guys have written a unit testing framework called nit that makes it fairly easy to write unit tests for your JavaScript code. This isn't anything new. nit also makes it easy to write unit tests for your Athena widgets, which is awesome. Here's how to do it.
1 Set up files and directories
Create the following files and directories.- foo/__init__.py
- foo/test/__init__.py
- foo/test/livetest_foo.js
- foo/test/livetest_foo.py
- foo/static/js/foo.js
- nevow/plugins/foopackage.py
2 Set up namespaces
Athena lets you put JavaScript files in namespaces, just like Python. However, unlike Python, you have to explicitly map namespaces to files.So, in nevow/plugins/foopackage.py:
from twisted.python import utilThis registers foo/static/js/foo.js as the 'Foo' namespace and foo/test/livetest_foo.js as the 'Foo.Tests' namespace.
from nevow import athena
import foo
def _f(*sib):
return util.sibpath(foo.__file__, '/'.join(sib))
fooPkg = athena.JSPackage({
'Foo': _f('static', 'js', 'foo.js'),
'Foo.Tests': _f('test', 'livetest_foo.js')})
3 Write A Single, Failing Test
Your test needs to have two parts: a JavaScript part and a Python part.In foo/test/livetest_foo.py:
from nevow import loaders, tagsThis is the hook for nit to catch on to your test. nit will render OurFirstTest as a LiveFragment and bind it to an instance of Foo.Tests.OurFirstTest.
from nevow.livetrial import testcase
class OurFirstTest(testcase.TestCase):
jsClass = u'Foo.Tests.OurFirstTest'
docFactory = loaders.stan(tags.div(render=tags.directive('liveTest'))['OurFirstTest'])
In foo/test/livetest_foo.js:
// import Nevow.Athena.TestThis is a weird way of writing JavaScript. Emacs hates it – it does the indentation all wrong, and no one at Divmod had a fix on hand. Anyway, it's all part of the desperate bid to turn JavaScript into Python. The run method gets called by nit when you click 'Run'. Observe!
Foo.Tests.OurFirstTest = Nevow.Athena.Test.TestCase.subclass('OurFirstTest');
Foo.Tests.OurFirstTest.methods(
function run(self) {
self.assertEquals('apple', 'orange');
});
$ nit foo
2006/05/24 11:26 EST [-] Log opened.
2006/05/24 11:26 EST [-] nevow.appserver.NevowSite starting on 8080
2006/05/24 11:26 EST [-] Starting factory <nevow.appserver.NevowSite instance at 0x1427990>
Hit http://localhost:8080/ and you'll see your test and a button. Hit the button. You'll see a big red traceback that shows that your test FAILS.
We have a single, failing test. However, it only does JavaScript stuff, which is boring.
4 Write A Single, Failing Widget Test
To test a widget, we need to create it and render it as a part of the test. Creating a widget requires writing a JavaScript part and a Python part. We'll also need to modify our test to actually call things on the widget.So, first, change livetest_foo.py:
from nevow import loaders, tagsThis creates the widget Bar and renders it as part of the test. However, before we implement the widget, let's finish writing the test: that is, the JavaScript part.
from nevow.livetrial import testcase
from foo import widgets
class OurFirstTest(testcase.TestCase):
jsClass = u'Foo.Tests.OurFirstTest'
docFactory = loaders.stan(
tags.div(render=tags.directive('liveTest'))[
tags.invisible(render=tags.directive('barwidget'))])
def render_barwidget(self, ctx, data):
widget = widgets.Bar()
widget.setFragmentParent(self)
return widget
// import FooAt this point, 'nit foo' will fail saying it can't import foo/widgets.py. Creating foo/widgets.py will let it run properly, but the page will render a stack trace indicating that widgets.Bar doesn't exist. Let's create it minimally. Put this in foo/widgets.py
// import Nevow.Athena.Test
Foo.Tests.OurFirstTest = Nevow.Athena.Test.TestCase.subclass('First');
Foo.Tests.OurFirstTest.methods(
function run(self) {
var bar = self.childWidgets[0];
self.assertEquals(bar.frotz(), 42);
});
from nevow import loaders, tags, athenaNow we can view the tests. However, running them will produce a failure, saying that 'bar' has no properties, referring to the bar in Foo.Tests.OurFirstTest.run. This is because we haven't yet written the JavaScript side of the widget. We've said the class is Foo.Bar, so we'll need to dump it in the Foo namespace which we've configured in foo/static/js/foo.js. Here it is.
class Bar(athena.LiveFragment):
jsClass = u'Foo.Bar'
docFactory = loaders.stan(
tags.div(render=tags.directive('liveFragment'))['Bar'])
// import Nevow.AthenaNow, run 'nit foo' again, hit your localhost and run the tests. You should see "Error: Test Failure: undefined != 42" at the top of your red traceback. You now have a single failing unit test for an Athena widget.
Foo.Bar = Nevow.Athena.Widget.subclass('Foo.Bar');
Foo.Bar.methods(
function frotz(self) {
});
- The code for Step 3
- The code for Step 4
Link | Leave a comment {2} | Add to Memories | Tell a Friend
Blog and Tech Blog
Apr. 3rd, 2006 | 11:05 am
Hacking stuff is going in blackjml
Everything else is in jml
I'll probably still put tech stuff in jml.lj.com and just cross-post to blackjml.
It's a difficult decision for me. On the one hand, Twisted itself has nothing to do with the books I'm reading, my political views or my theological reflections. On the other hand, hacking on Twisted is part of my life of ministry and one of the ways that I worship God.
So, I've made my decision based on personal ease. I struggle to write in my blog about the things that I'm actually thinking about, that really influence me. I feel that I have to navigate through the minefield of misconceptions that people have about evangelical Christianity. I want to make the rest of my blog easy for the people are reading my blog solely because of my participation in Twisted. On reflection, I think it instead becomes cumbersome and verbose for everyone.
However, if people are reading my blog based on some interest in me, then the task of resolving misconceptions can be shared.
