James Tauber's Blog 2008/05


blog > 2008 >


Question-Driven Commenting

I've always loved Titus Brown's notion of stupidity driven testing. It's okay to make a mistake but you write a test to make sure you don't do it again.

With Pinax, I've been adopting the sister practice of "question-driven commenting". When someone asks me what a function does or how to implement a particular extension, that's when I go and add comments to the code.

Of course, the person asking the question could be me :-)

by : Created on May 28, 2008 : Last modified May 28, 2008 : (permalink)


Pinax Progress II

Yesterday I reported that we'd added the following to Pinax in the last 24 hours:

Well, in the last 24 hours we've added to that:

I could not have hoped for a more productive weekend!

Earlier in the day I did a rough count purely based on file-size and estimated that Pinax is:

which bodes well for the original goal of Pinax: to jump-start some reusable Django apps.

by : Created on May 26, 2008 : Last modified May 26, 2008 : (permalink)


Pinax Progress

Here is what the team of brosner, leidel, floguy and myself have added to Pinax in the last 24 hours:

Check it out at http://pinax.hotcluboffrance.com/

by : Created on May 25, 2008 : Last modified May 25, 2008 : (permalink)


Programming as Jazz

I'm starting to appreciate that programming has more similarities to Jazz than just the project naming conventions encouraged by Django.

When I started the Hot Club of France mailing list (named for Django Reinhardt's Quintet du Hot Club de France) I explicitly mentioned it was about writing reusable apps that "jam" well together. But I'm realising that it's as much about the developers jamming as the code itself.

Ever since the inception of the Hot Club project, I've thought about cloning Web 2.0 websites using reusable Django projects. I noticed at the time that this is sort of like the "contrafact" approach of early Jazz where you would improvise new songs using the chord progressions of existing songs. The analogy isn't perfect but I do think the term "contrafact" is a great one to use for the programming practice.

Things are really starting to come together with Pinax and the conversations I've been having recently with other Django developers keen to jam with me on it reminds me a lot of stories I've read of the bebop years. You check out someone's work, think it will work well with your own style and start doing some improv together. Awesome stuff!

Things are really starting to come together at http://pinax.hotcluboffrance.com/

Just call me yardbird :-)

by : Created on May 23, 2008 : Last modified May 23, 2008 : (permalink)


Funcom's Epic Fail

So the other night I decided to purchase the adventure game Dreamfall by FUNCOM as a digital download. They provide their own downloader, that's fine. But

EPIC FAIL FUNCOM!

by : Created on May 22, 2008 : Last modified May 22, 2008 : (permalink)


Creating Gradients Programmatically in Python

For various sites I often want to create a narrow gradient image. This site has two, for example, the grey background gradient and the purple header gradient.

Rather than having to open up a drawing tool every time I want to create one of these, I thought I'd write a Python script to generate a PNG of a gradient according to declarative specifications.

The result is

http://jtauber.com/2008/05/gradient.py

Only linear gradients are currently supported although you can have any number of them at different vertical offsets and it's easy to modify the code to support other gradient functions.

The code itself is 50 lines long and has no dependencies other than the standard library. I've included some samples based on the gradients on jtauber.com and Pinax.

For example, this gradient:

is produced with the following code:

write_png("test2.png", 50, 90, gradient([ (0.43, (0xBF, 0x94, 0xC0), (0x4C, 0x26, 0x4C)), # top (0.85, (0x4C, 0x26, 0x4C), (0x27, 0x13, 0x27)), # bottom (1.0, (0x66, 0x66, 0x66), (0xFF, 0xFF, 0xFF)), # shadow ]))

The 30-line write_png function could also be used more generally for generating any RGB PNGs.

by : Created on May 18, 2008 : Last modified May 18, 2008 : (permalink)


Metrics Provide An Inner Product

Another post for the Poincaré Project.

We've already seen that a one-form is a linear function from a vector to a (for our purposes) real number. On a manifold, one-forms correspond to stack-type vectors being applied to arrow-type vectors by counting how many "stacks" the arrow passes through.

In the previous post Metrics As Mappings Between Arrows and Stacks, we saw that a metric is an extra bit of structure that describes how to map between arrow-type vectors and stack-type vectors.

So, in summary:

These two facts can be combined to let you take two arrow-type vectors and get a real number out of them.

This has parallels with currying in functional programming.

Recall that if a function "add" takes two integers and returns an integer, it can be viewed as a function that takes one integer and returns a function that takes one integer and returns an integer.

add :: Int -> Int -> Int

Now, a one-form is a function that takes a vector and returns a real. In other words:

Vector -> Real

So it is easy to see that if you curry a real-valued function that takes two vectors you get:

Vector -> Vector -> Real

In other words, a function taking two vectors to a real is equivalent to a function from a vector to a one-form.

So if you have a metric that can convert between vectors and one-forms (or, in the context of a manifold, between arrows and stacks) then you also have a function from two vectors to a real.

Such a function is called an inner product or dot product. Often the notion of an inner product is defined first, before one-forms are introduced (if at all). In fact, some texts will define a metric to be an inner product. It is best for our purposes, though, to think of the metric's fundamental purpose as being converting between arrows and stacks (and back again) and the inner product as being an extra concept we get for free.

by : Created on May 11, 2008 : Last modified May 11, 2008 : (permalink)


Introducing Pinax

In the post Reusable Django Apps and Introducing Tabula Rasa I mentioned my project to create an out-of-the-box Django-based website with everything but the domain-specific functionality.

At the time I was calling it Tabula Rasa but now I've settled on the Greek word Pinax, proposed by Orestis Markou.

So far it's just my new django-email-confirmation app tied together with password change and reset, login/logout, with the beginnings of a tab-style UI. There's a ton more I want to refactor out of my existing websites to put into it as well as adding support for OpenID and the stuff I'm starting to do for django-friends.

Even if one doesn't use Pinax as the starting point of a website, I'm hoping it will prove very useful for another goal, namely a "host" project to develop and tryout reusable apps.

The initial code is available at http://code.google.com/p/django-hotclub/ under /trunk/projects/pinax and there is a running instance for you to try out at:

http://pinax.hotcluboffrance.com

by : Created on May 10, 2008 : Last modified May 10, 2008 : (permalink)


Elite Oolite

When I lived in Brunei in the mid-80s, a neighbour had a BBC Micro and I would go over there to play the space trading game Elite. The hidden-line wireframe graphics and massive procedurally-generated universe seemed amazing to me at the time and it was definitely the kind of software I aspired to one day write myself. At the time, I taught myself trigonometry to do 3D graphics but never got to hidden line removal :-)

I was aware of various Elite clones over the years, but the other day I stumbled across Oolite, an open-source Mac OS X version with modern OpenGL graphics. Simply amazing and just as addictive as I remember the original being. It also seems to be highly pluggable, with numerous extensions available to add both to the UI and gameplay.

by : Created on May 9, 2008 : Last modified May 9, 2008 : (permalink)


LOTRO on VMware Fusion

I've hardly played Lord of the Rings Online at all the last six months and not at all the last three.

My only copy of Windows is a VMware Fusion instance and LOTRO doesn't work on VMware Fusion. That is...until now.

I was excited to hear that the new VMware Fusion 2.0 beta 1 supported pixel shaders in DirectX 9 and I wondered if that meant LOTRO would work. I downloaded the beta, which JUST WORKED with my existing VM (which wasn't even shut down). I spent an hour or so updating LOTRO but my first attempt to start the game failed.

The error message was different, though. Instead of being about the graphics adapter it was a complaint about a Game Error 127. A Google search revealed this post and so I tried making the config change they suggested there.

And BINGO! I can now run Lord of the Rings Online on VMware Fusion!

I haven't tweaked the settings yet to see if it's playable but I'm hopeful.

VMware, you are amazing!

UPDATE: I played LOTRO for a little bit tonight. I had to turn sound off as it was too jittery. Graphics were fine, though, on Low detail and low resolution. The mouse look problem mentioned in the comments was easily fixed by just going to options and changing the mouse look sensitivity.

by : Created on May 6, 2008 : Last modified May 6, 2008 : (permalink)


Reusable Django Apps And Introducing Tabula Rasa

The excellent 42 Topics blog has a post entitled Popularizing Django — Or Reusable apps considered harmful which makes (or attempts to make) the case for packaged apps over reusable apps.

He raises some good points, although of course the packaged apps he's talking about still use reusable apps so he's not actually talking about there being a problem with reusable apps per se, just that there should be packaged apps as well.

I mentioned the django-hotclub group in a comment on that post as I'd really like the discussion to take place there.

I also, in that comment, mention something I'm working on tentatively called Tabula Rasa. (I'm toying with a Greek name rather than Latin but something tells me people are more comfortable with tabula rather than grammateion)

Basically, the goal of Tabula Rasa is an out-of-the-box Django-based website with everything but the domain-specific functionality.

So far it's just my new django-email-confirmation app tied together with password change and reset, login/logout, with the beginnings of a tab-style UI. There's a ton more I want to refactor out of my existing websites to put into it as well as adding support for OpenID and the stuff I'm starting to do for django-friends.

Even if one doesn't use Tabula Rasa as the starting point of a website, I'm hoping it will prove very useful for another goal, namely a "host" project to develop and tryout reusable apps.

One of the challenges I know I've always had with writing or trying out reusable apps is the need for a project to provide the scaffolding.

So Tabula Rasa will hopefully serve that dual purpose.

UPDATE: I've decided to switch to the Greek word pinax suggested below by Orestis Markou.

UPDATE 2: Now see Introducing Pinax.

by : Created on May 6, 2008 : Last modified May 9, 2008 : (permalink)


Metrics As Mappings Between Arrows and Stacks

Another post for the Poincaré Project.

Back in Coordinate Systems and Metrics we saw that a metric for a coordinate system tells us the "distance travelled as proportion of coordinate change". Then in the following post, Metrics in Two or More Dimensions:

Imagine that you're at a particular point on a two-dimensional manifold. If you head off in a particular direction from that point at a particular rate, your coordinates will change. The metric tells you, from a given point, the rate of change of each of your coordinates given travel in a particular direction at a particular rate.

Those two posts express two sides of the same coin: in one I said the metric tells us the rate of change of position given the rate of change of coordinates and in the other I said the metric tells us the rate of change of coordinates given a rate of change of position.

A rate of change of position is, as we've seen, an arrow-vector. A rate of change of a particular coordinate is, as we've also seen, a stack-vector in the dual space.

In fact, one can view a metric as being a mapping between arrow-vectors and stack-vectors. You can use it, along with some calculus if the metric is different at different points, to calculate distances (as described in Coordinate Systems and Metrics). It can also be used to calculate the length of a vector or the angle between two vectors (concepts which don't exist without a metric).

A metric ties those length and angle notions to the coordinate system and, in so doing, actually defines the coordinate system.

Finally, a metric has within it, all the information necessary to describe the curvature of a manifold. It is ultimately this function that makes it relevant to both the General Theory of Relativity and the Poincaré Conjecture.

We will explore each of these in due course. The main takeaway at this point is that a metric is a mapping between arrow-vectors and stack-vectors.

by : Created on May 4, 2008 : Last modified May 4, 2008 : (permalink)


Factoring Out Common Args To Zipped Generators

I'm playing around with some additive synthesis in Python.

I've implemented an oscillator as a generator that takes a number of parameters. It is then possible to mix multiple oscillators using zip (or better, itertools.izip) over them and doing a (weighted) sum.

However, I wanted to be able to factor out common arguments to the oscillators so I didn't have to specify the frequency of each one individually.

I knew functools.partial would be part of the solution but it took me a while to work out how to combine its use with generators and itertools.izip.

Here is a simplified progression of what I came up with.

Phase 1

Rather than use oscillators, let's just imagine with have a generator that works a lot like xrange:

def gen1(start, stop, step): n = start while n <= stop: yield n n += step

then we can combine multiple generators and, say, sum the corresponding elements like this:

for x in zip(gen1(10, 20, 2), gen1(10, 25, 3)): print sum(x),

Phase 2

Let's abstract this into a function that takes generators as arguments (and uses itertools.izip)

def mixer1(*generators): return (sum(x) for x in izip(*generators))

for x in mixer1(gen1(10, 20, 2), gen1(10, 25, 3)): print x,

mixer1 is similar to my mixer (although without weighting)

Phase 3

But now say we wanted to factor out the common start parameter. First we need a partial version of function gen1:

gen2 = lambda **kwargs: partial(gen1, **kwargs)

This allows one to say

partial_gen = gen2(stop=20, step=2)

and then later call

partial_gen(start=10)

to get the generator.

But what we now need is a new version of the mixer that takes the extra keyword args and passes them in to each partial function to turn them back into generators:

def mixer2(*generators, **kwargs): return mixer1(*[gen(**kwargs) for gen in generators])

and now we can say:

for x in mixer2(gen2(stop=20, step=2), gen2(stop=25, step=3), start=10): print x,

Phase 4

Here's the final version:

gen2 = lambda **kwargs: partial(gen1, **kwargs)

def mixer3(*generators, **kwargs): return (sum(x) for x in izip(*[gen(**kwargs) for gen in generators]))

The real thing is a little more involved because of the weighted summing, etc but the hard parts are shown.

by : Created on May 2, 2008 : Last modified May 3, 2008 : (permalink)


Moiré Waves

I was playing around with some additive synthesis in Python, generating various basic waveforms and checking them visually, in Soundtrack Pro.

The moiré pattern of the waveforms in one test file was interesting:

That's actually 220 cycles of a sine wave, followed by the same for a sawtooth, square and triangle waveform.

by : Created on May 1, 2008 : Last modified May 1, 2008 : (permalink)