James Tauber

journeyman of some

blog >

James Tauber's Blog 2008

Changes to Google Maps Satellite Images

It used to be obvious in Google Maps where the boundaries of different satellite images were. Each image had different brightness, contrast, colour, etc which gave away the stitching.

I always wondered whether there were techniques to normalize that.

I guess there are: Today I noticed the satellite images are stitched together seamlessly.

I also noticed some level-of-detail differences between land and ocean and that is also done pretty seamlessly.

It actually makes navigating around the satellite view a little eerie.

Anyone know when the change was made?

UPDATE: Actually it depends on the zoom level. Compare this to this. And notice the image credits are different. Interestingly, my home town of Perth looks fully normalized at all scales, even though the image sources are still TerraMetrics for the large scale and DigitalGlobe/GeoEye for the small scale.

by jtauber : Created on July 4, 2008 : Last modified July 4, 2008 : Categories google : 2 comments (permalink)

The Annotated Turing

Some books entertain, some inform; some confirm what you already knew, some make you change your mind about something. But then there are some books that just make you think "wow! I wish I'd written that".

For me, Charles Petzold's The Annotated Turing falls into that last category. It's a book worth reading not only for the topic itself but the way it's presented.

He provides the necessary background before working through Turing's famous 1936 paper "On computable numbers, with an application to the Entscheidungsproblem" with rich annotations at every stage, including biographical details.

If you are interested in the foundations of mathematics, computability, Turing's work, or even just ways of explaining mathematics in a historical context, I highly recommend this book.

by jtauber : Created on July 3, 2008 : Last modified July 3, 2008 : Categories mathematics books : 0 comments (permalink)

Pinax Progress III

In the six weeks that it's been around (that's not six weeks since launch, that's six weeks since coding started), the Pinax platform and community has grown in ways I never expected.

Since I last blogged about it, we've added:

  • localization into Brazilian Portuguese and Hebrew
  • timezone localization
  • external blog aggregation
  • wikis
  • threaded discussions
  • bookmarks with voting
  • contact import
  • blogs with tagging and threaded comments

It is becoming clear that what was originally intended to be a demo site is a useful site in its own right, irrespective of whether you care or even know about the Pinax platform underlying it. So it will be moving over to a new site with a new identity soon.

by jtauber : Created on July 2, 2008 : Last modified July 2, 2008 : Categories django pinax : 0 comments (permalink)

Back to Blogging

Last month was my worst blogging drought ever.

It happened for a number of reasons: I was travelling almost 3 weeks out of the month; free time was spent on other projects; Twitter replaced a lot of my drive to blog (and subsequently, the django-hotclub IRC channel replaced a lot of my drive to Twitter).

I'm going to try to blog a lot more regularly this month. I have a long list of things to blog about.

by jtauber : Created on July 1, 2008 : Last modified July 2, 2008 : Categories blogging : 0 comments (permalink)

Two Podcast Interviews

In the last week two podcasts have come out which I appear on.

The first is the Google Summer of Code podcast where Titus Brown and I were interviewed about the Python Software Foundation's participation in both GSoC and GHOP.

http://google-opensource.blogspot.com/2008/05/podcast-with-pythonistas.html

The second is This Week in Django where I talk a little about myself and (more importantly) Pinax and the Hot Club of France.

http://blog.michaeltrier.com/2008/6/2/this-week-in-django-24-2008-06-01

I sound much better in the second one because I recorded my track locally with a large diaphragm condenser mic and sent the audio file for mixing. In the first one, it's just my laptop mic going over Skype.

They were both fun although I babble too much, especially on the TWiD podcast.

by jtauber : Created on June 4, 2008 : Last modified June 4, 2008 : Categories python django summer_of_code pinax : 0 comments (permalink)

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 jtauber : Created on May 28, 2008 : Last modified May 28, 2008 : Categories software_craftsmanship : 7 comments (permalink)

Pinax Progress II

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

  • user profile pages
  • gravatars
  • user-to-user messages (via django-messages)
  • announcements (a new app, django-announcements)
  • OpenID support
  • invitations to join

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

  • translations into German, Spanish and Swedish
  • a new design / logo
  • auto-completion on message recipient field
  • a basic Twitter clone
  • OEmbed support in tweets
  • the beginnings of tribes (i.e. groups)

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:

  • 63% re-usable apps;
  • 10% local app;
  • 13% templates;
  • 8% localization;
  • 5% media;
  • 1% util

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

by jtauber : Created on May 26, 2008 : Last modified May 26, 2008 : Categories django pinax : 1 comment (permalink)

Pinax Progress

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

  • user profile pages
  • gravatars
  • user-to-user messages (via django-messages)
  • announcements (a new app, django-announcements)
  • OpenID support
  • invitations to join

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

by jtauber : Created on May 25, 2008 : Last modified May 25, 2008 : Categories django pinax : 3 comments (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 jtauber : Created on May 23, 2008 : Last modified May 23, 2008 : Categories django software_craftsmanship pinax : 0 comments (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

  • the downloader first requires you to install .NET 2.0 yourself
  • the downloader prompts you to enter "the provided key" but the email receipt from FUNCOM didn't mention the word "key". It had something it called a "license number".
  • I typed in the license number but the downloader came back "invalid coupon" (I'm thinking at this stage "is it a key, a number or a coupon" ?!?!)
  • the receipt says to email marketing@funcom.com if there are any problems with digital downloads so I email that address
  • I get back an autoresponse saying "If you have not submitted this via our web form at [link provided] then your mail may be removed by our spam filter. Please resubmit your request using this form."
  • I click on said link and get a 404.

EPIC FAIL FUNCOM!

by jtauber : Created on May 22, 2008 : Last modified May 22, 2008 : 3 comments (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 jtauber : Created on May 18, 2008 : Last modified May 18, 2008 : Categories python web_design : 8 comments (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:

  • a metric tells you how to go from an arrow-type vector to a stack-type vector
  • a stack-type vector can be applied to another arrow-type vector to get a real number

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 jtauber : Created on May 11, 2008 : Last modified May 11, 2008 : Categories poincare_project : 0 comments (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 jtauber : Created on May 10, 2008 : Last modified May 10, 2008 : Categories django pinax : 7 comments (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 jtauber : Created on May 9, 2008 : Last modified May 9, 2008 : Categories games : 0 comments (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 jtauber : Created on May 6, 2008 : Last modified May 6, 2008 : Categories os_x lotro : 4 comments (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 jtauber : Created on May 6, 2008 : Last modified May 9, 2008 : Categories django : 9 comments (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 jtauber : Created on May 4, 2008 : Last modified May 4, 2008 : Categories poincare_project : 0 comments (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 jtauber : Created on May 2, 2008 : Last modified May 3, 2008 : Categories python : 1 comment (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 jtauber : Created on May 1, 2008 : Last modified May 1, 2008 : 2 comments (permalink)

Grammar Rules

One downside to having a background in linguistics is that one is more sensitive to various so-called grammar rules that people regurgitate from their school years.

The majority of linguists probably view these rules the way a doctor would view the four humours. But a more fundamental issue is not that some of the theories have been superseded but that their perpetuation reveals a very unscientific approach to language. It is as if these people are viewing rules of grammar like they would road rules—human inventions that one may disagree with, but which are still, in some sense, what is "correct"—rather than, say, laws of physics that attempt to model observations.

This means that when confronted with data that doesn't match the rules, such people will say the data is wrong ("that isn't correct English") rather than ever consider that maybe it's their rules that need refinement.

Now it is certainly the case that people make mistakes when they speak (and that can be a revealing study in itself) and there is such a thing as good English usage (see the last paragraph) but most linguists focus on modeling the tacit intuitions native speakers have about their language which are very often at odds with the "rules of grammar" learnt at school.

Let me give an example. A common misconception is that English has cases that work in a similar way to Latin. I suspect the origins of this stem from attempts to model English after Latin as if Latin was somehow a better language.

It is easy to see on the surface there might be evidence for a nominative/accusative case distinction in English pronouns. Native speakers will say "I gave the book to him. He gave the money to me." with the intuition that switching "I" and "me" or "he" and "him" would be incorrect. This is a valid observation that a linguist would want to capture in some kind of descriptive rule.

However, when asked "who is it?" native speakers will almost always answer "it's me" rather than "?it's I".

I've had people try to tell me that the latter is "more correct" although they don't say it themselves. If they don't say it, as competent speakers of English, what is their claim to it being correct? Because their high school English teacher told them? Because Latin would use the nominative here?

If you ask a group of people "who wants to sit in the front?" they are far more likely to answer "me" than "?I". And yet they would say "I do" rather than "*me do". If you accuse someone you are probably more likely to say "it was him" not "?it was he". So what's going on doesn't just involve using the nominative case for the subject and accusative case for the object.

The massive 1,800+ page Cambridge Grammar of the English Language gives more great examples "nobody can do it but her/*she", "the only one who objected was me/?I" and (showing photos) "this one here is me/*I at the age of 12".

Things become even more complex in the case of conjunctions. The Cambridge Grammar gives the example of "they invited my partner and I to lunch". They point out that examples like this "are regularly used by a significant proportion of speakers of Standard English, and not generally thought by ordinary speakers to be non-standard". They go on to argue against the prescriptivist use of analogy with "they invited me/*I to lunch" to justify why the use of "I" is incorrect.

The worst kinds of rules are ones that sound almost like superstitions: don't use passives, don't use adverbs, don't split infinitives, don't end sentences with a preposition, don't start a sentence with "however" etc. They may help one adopt a particular style of writing, but they certainly aren't rules of grammar in any scientific sense and are, in most cases, completely arbitrary.

Some of the usage guides these rules are found in are better than others. Strunk and White is full of these arbitrary superstitions. In fact, Professor Geoffrey Pullum, the co-editor of the previously mentioned Cambridge Grammar of the English Language describes Strunk and White as a "horrid little notebook of nonsense" and instead recommends Merriam-Webster's Concise Dictionary of English Usage which I own and agree is much more useful for evidence-based guidelines on subtle differences in usage between words.

by jtauber : Created on May 1, 2008 : Last modified May 1, 2008 : Categories linguistics linguistic_observations : 14 comments (permalink)

UPS Invents Time Travel

and who is BERT in Provo?

by jtauber : Created on April 30, 2008 : Last modified April 30, 2008 : 2 comments (permalink)

Why Colour Correction Only Needs Two Sliders

Duncan Davidson (who I still think of as James) asked on Twitter:

Color Temp works on the Blue/Yellow axis. Tint on the Green/Magenta. No need to tweak Red/Cyan?

I responded there but decided to here as well as I've talked about colour theory before.

The basic answer is that you only need two axes because colour (disregarding brightness/luminance) is two-dimensional. Red, Green and Blue form a triangle in that two-dimensional space (with Cyan, Magenta and Yellow being on the opposite edges respectively).

Basic linear algebra tells us that, in an n-dimensional space, you only need n vectors to form a basis (actually, that's the definition of dimensionality) so you can adjust any point in two-dimensional colour space by translating it by a linear combination of any two, non-parallel vectors. Incidentally, Hue and Saturation would be almost polar coordinates on this space.

Because one form of colour modification is colour temperature, it makes sense to roughly make one of the axes the yellow-blue direction. I think the magenta-green axes is largely arbitrary. Any other axis would have done fine.

Note I say "roughly" the first time in that previous paragraph because the black-body colours aren't a straight line in standard colour models.

Hmm, that makes me wonder if colour correction sliders represent rectilinear bases at all.

UPDATE (2008-05-04): According to a reply in the Reddit thread, the slides aren't rectilinear but are based on the black-body colours. The so-called "tint" is presumably then orthogonal to black-body line (the Planckian locus)

by jtauber : Created on April 29, 2008 : Last modified May 5, 2008 : Categories photography : 10 comments (permalink)

Auto-Scrolling in jQuery

I mentioned in my previous post New Site Look that, inspired by 37 Signals, I wanted to auto-scroll pages in my website in two circumstances:

  • when there is an error in an Add Comment form, scroll down to the error message
  • when the user expands the Add Comment form, scroll to put the form in view

Here's the fragment of my Django template that achieves both of these with jQuery:

<script type="text/javascript" src="/static/jquery.js"></script>
<script type="text/javascript">
    function scrollTo(selector) {
        var targetOffset = $(selector).offset().top;
        $('html,body').animate({scrollTop: targetOffset}, 500);
    }
    $(document).ready(function() {
        $('#add_comment_toggle').click(function() {
            $('form.add_comment').slideToggle();
            scrollTo('form.add_comment');
            return false;
        });
        {% if comment_error %}
        $('form.add_comment').show();
        scrollTo('.comment_error');
        {% endif %}
    });
</script>

The only bit of Django, for those who don't know it, is the {% if ... %} which only includes that Javascript if a comment_error exists.

The scrollTo function scrolls to the element whose selector is given. Notice how, if a comment_error exists, I make sure the form is showing first, then call scrollTo.

Also, in my code for toggling the Add Comment form, I call the function to scroll to the form.

by jtauber : Created on April 28, 2008 : Last modified April 28, 2008 : Categories django web_design javascript jquery : 6 comments (permalink)

New Site Look

If you read this in a feed reader, you might want to go to my actual site to see what I'm talking about :-)

Usually, when I rewrite the underlying code behind jtauber.com, I do a redesign of the look as well. In the 14 years that jtauber.com has been around, it's probably had around 10 different looks. The last change took place when I wrote Leonardo in 2003.

When I ported Leonardo to Django I really should have changed the look, in keeping with tradition, but I didn't. I decided this weekend to do some code clean up and add a couple of new features and ended up doing a completely new look as well. I also switched from Django 0.96.1 to Django trunk (including qs-rf), although I don't make use of any of the new features yet.

Here's a brief list of what I did change:

  • changed colour from the green I've had for the last five years to a purple more like what I had in 2002 but with lickable gradient site title
  • went from a two-column to three-column layout so I'd have a place to put some Web 2.0 goodies on every page
  • added my photo to the home page :-)
  • added Twitter updates
  • added links to my Facebook and LinkedIn profiles
  • added an overflow property to pre so code examples don't overlap the right column
  • fixed an annoying bug where if you got the maths question wrong your comment would get forgotten
  • made add comment form initially hidden and available only via a toggle
  • inspired by this video at 37 Signals, I added some auto-scrolling to the add comment form—when there is an error in submission, the page automatically scrolls to the errors; and when you toggle the comment form open, it automatically scrolls so the form is fully in view.

Had to trigger hasLayout in IE6 to get it to work there. Fortunately, I'd had that issue previously with Quisition so knew what to do. Thank goodness for VMware Fusion to enable me to check the site on IE6.

I quite like the new look, especially in comparison to the old look. I'm more than a little chuffed at getting the autoscrolling working too :-)

by jtauber : Created on April 27, 2008 : Last modified April 27, 2008 : Categories django this_site web_design : 4 comments (permalink)

django-email-confirmation

This simple django app is for cases where you don't want to require an email address to signup on your website but you do still want to ask for an email address and be able to confirm it for use in optional parts of your website.

A user can have zero or more email addresses linked to them. The user does not have to provide an email address on signup but, if they do, they are emailed with a link they must click on to confirm that the email address is theirs. A confirmation email can be resent at any time.

As of r22, what's on the trunk here should be usable but I welcome feedback on how to make it better. The source contains a working project that shows all the features of the app as well as providing useful code for your own project.

This code is based in part on django-registration and is essentially a replacement for it where your requirements are different.

http://code.google.com/p/django-email-confirmation/

by jtauber : Created on April 27, 2008 : Last modified April 27, 2008 : Categories django : 0 comments (permalink)

Barry and Frank

Continuing on from the previous Barry and Frank story...

Colin comes up to Barry and Frank and says "I've just tossed this coin 100 times and recorded the result each time in this notebook. What is the probability that toss number 37 was tails?". Frank thought for a moment and asked "can we study the notebook?" "Sure," Colin said.

Frank took the notebook and looked through it before declaring "well, 40 out of 100 tosses were tails, so the probability of toss number 37 having been tails is 0.4".

"I agree," said Barry, somewhat to the surprise of Frank. But Barry then took the notebook, turned to the appropriate entry and said "oh, the probability just changed to 1"

by jtauber : Created on April 17, 2008 : Last modified April 17, 2008 : Categories mathematics : 1 comment (permalink)

Probability Thought of the Day

If I ever taught probability and statistics, this is the problem I'd put on the board the first lecture:

Colin comes up to Barry and Frank and says, "hey guys! I have a coin here which is biased but I won't tell you which way or by how much. What's the probability of the next toss being tails?". Barry replied, "given what we know, it is 0.5". Frank looked astonished. "How can you say 0.5? Given the coin is biased, that's the one probability we know it can't be." Who is right, Barry or Frank?

UPDATE: corrected "a tail" to "tails".

UPDATE 2: Eliezer Yudkowsky has a great post on exactly this scenario. He's way smarter than I, so go read him :-)

by jtauber : Created on April 13, 2008 : Last modified April 13, 2008 : Categories mathematics : 21 comments (permalink)

History

via James Bennett and Bill de hÓra:

$ history | awk '{print $2}' | sort | uniq -c | sort -rn | head
 120 cd
 111 ls
  78 python
  73 svn
  17 mate
  14 less
  11 rm
  11 mv
   7 mkdir
   5 ssh

No surprises there at all :-)

by jtauber : Created on April 10, 2008 : Last modified April 10, 2008 : 0 comments (permalink)

More About Twitter

On my previous entry about Twitter, Nelson commented:

I still don't really get what Twitter is... would it be useful to me?

I could describe Twitter as to blogging what IM is to email but that's not enough.

I admit that I didn't get Twitter at first. For months I just thought it wasn't my kind of thing.

Then something changed.

For me Facebook status was the gateway drug. Once I got interested in what people were doing, thinking, and responding to in their Facebook status, Twitter started to make more sense.

The other thing that changed was I built a critical mass of interesting people to follow. Some of them were people I only vaguely know but who I knew had interesting things to say. Some I confess are just fly-on-the-wall eavesdropping.

But the two most interesting categories are the friends who I can keep more in touch with about day-to-day stuff and the acquaintances (or strangers) with common interests who I strike up spontaneous conversations with.

Here is fun example last week. Someone mentioned that Game Neverending (GNE) was back. So I went and checked it out. It closed down a couple of hours later so I never would have known about it in time if not for Twitter. Later on in the week, I twittered that I'd like to write a GNE-clone in Django. As well as a number of people asking me what GNE was, I also had a reply from a guy I met at PyCon saying he'd love to be involved. So we worked on it together over the weekend (see my post about it. All this happened because of Twitter.

To build the critical mass of people to follow (what I did, anyway):

  • if you're on Facebook, see which of your friends are twittering and start following them
  • import your contacts (I did this via gmail even though I don't use gmail) to see other friends who twitter
  • look at who your friends are following and start following some of those people
  • look to see who your followers are replying to and start following them
  • if someone follows you, check them out and, if they're not spam, follow them

The other thing that helped me get into it was finding a client app. I've used Twitterific and Twhirl and like both a lot.

Incidentally, I twittered that I was writing this post and immediately received a number of suggestions and links (thanks @moof and @epoz)

Suggested blog posts on this topic included:

I'll also twitter with a link to this post for people to add their comments to.

Will it be useful to you? If you like finding out what friends are up to; if you like learning about new things going on from smart people with common interests; if you like making serendipitous connections based on overheard conversations, then Twitter will be useful to you.

Hope this helps!

P.S. If you follow a lot of people, never be afraid to just ignore the river of tweets when you're busy (or sleeping). I generally don't look at Twitter at work, for example, and only rarely ever go back to skim what I missed.

UPDATE: Definitely watch the short video http://www.commoncraft.com/Twitter that David recommends below!

by jtauber : Created on April 7, 2008 : Last modified April 7, 2008 : 6 comments (permalink)

Game Neverending in Django

In the early hours of April 2nd I heard via Twitter that Game Neverending, the online game that never launched but which gave rise to Flickr, had come back. I played it for about an hour and loved it but then had to go to work. When I got home, the game had been shut down again—I guess it was just an April Fool's joke.

Digging around I found the GNE museum which had a fair amount of information about the game mechanics. It occurred to me that it would be fairly straightforward to implement most of the concepts as a Django-based website.

So yesterday, I started django-mmo at Google Code Project Hosting. So far I've implemented the basic location system and support for some aspects of game items (player inventory, picking up and dropping, spawning but not the making system yet). I haven't paid any attention yet to UI (sort of looks like Web pages did in 1993) and the whole thing so far is played in a kind of "God-mode" where you can control any player. In a way, the UI is just there for testing the model at the moment.

But I'm making good progress. The initial goal is parity with GNE (or at least what I can glean from GNE museum) and then I can think about ways of extending it.

UPDATE (2008-04-13): Making and chat are now implemented. The UI is getting close to parity too.

by jtauber : Created on April 6, 2008 : Last modified April 14, 2008 : Categories python django games : 1 comment (permalink)

Twittering

I've been using Twitter a lot lately. My page is http://twitter.com/jtauber if you'd like to follow me.

I've also set up a Twitter account for Quisition and over the weekend plan to hook up notifications so that @quisition will tweet when there are new announcements and new packs.

And speaking of Quisition, I've created a Facebook page where I'll also post updates.

by jtauber : Created on April 4, 2008 : Last modified April 4, 2008 : 1 comment (permalink)

April Fools

Best Joke I Fell For

Tim Ferriss announcing he's been outsourcing his blog writing the last year.

What was brilliant about this was that I felt duped even before I realised it was a joke. Then I felt double-duped :-)

Best Joke I Didn't Fall For

YouTube Rickrolling.

Read about it on TechCrunch before I went to YouTube (not that I look at the featured videos anyway).

Best Joke With Just A Touch Of "Maybe They Aren't Completely Joking"

Google and Virgin joining forces to colonize Mars.

Who knows what parts of this they may actually be planning?

by jtauber : Created on April 2, 2008 : Last modified April 2, 2008 : Categories humour : 0 comments (permalink)

Thunks, Trampolines and Continuation Passing

Here is a thunk, a kind of delayed apply that takes a function and arguments but, rather than calling the function right away returns another function that, when called, will call the first function with the arguments originally given.

thunk = lambda name, *args: lambda: name(*args)

Here is a trampoline that basically unwraps nested thunks until a result is found.

def _trampoline(bouncer):
    while callable(bouncer):
        bouncer = bouncer()
    return bouncer

Here is a useful wrapper function that turns a function into a trampolined version.

trampoline = lambda f: lambda *args: _trampoline(f(*args))

Now let's just define one more ingredient, an identity function.

identity = lambda x: x

Now we can write factorial in continuation-passing style:

_factorial = lambda n, c=identity: c(1) if n == 0 else thunk(_factorial, n - 1, lambda result: thunk(c, n * result))

and trampoline it:

factorial = trampoline(_factorial)

We now have a factorial function that doesn't have stack limitations. You can say

print factorial(100000)

and (a couple of minutes later) Python will happily display the result :-)

I did consider currying thunk:

thunk = lambda name: lambda *args: lambda: name(*args)

so the CPS factorial would be:

_factorial = lambda n, c=identity: c(1) if n == 0 else thunk(_factorial)(n - 1, lambda result: thunk(c)(n * result))

UPDATE: Sorry to the first few commentors, due to a cute-and-paste SNAFU I was using the curried version of thunk for the first definition of _factorial. Now fixed.

by jtauber : Created on March 30, 2008 : Last modified March 30, 2008 : Categories python algorithms : 11 comments (permalink)

Coordinate Systems and Stack-Type Vectors

(on a bit of a roll with the Poincaré Project recently)

Back in 2006, I talked about the notion of a coordinate system which, for some region of a manifold, provides a tuple of real numbers identifying each point in that region. The mapping is homeomorphic so the coordinate system is continuous.

You can think of each component of the tuple as a separate function that maps from a point on the manifold to a real number. So, for a two-dimensional manifold, there's an x-coordinate function and a y-coordinate function that respectively tell you the x-coordinate and y-coordinate of a given point. The tuple for point p is then just (x(p), y(p)). The situation for a three-dimensional manifold is similar, you just need a third coordinate function. (Note these functions aren't inherent to the manifold, they are structure added to a manifold and you can, of course, have any number of alternative coordinate systems for the same region of a manifold.)

Each of these coordinate functions is no different than something like temperature or electric potential. They are all scalar fields—continuous real-valued functions on a region of a manifold—that give a real value for every point in that region in a way that if you traveled along a continuous path through the manifold, the value would change continuously.

Now say we wanted to describe how one of these coordinate functions changes as one moved in a particular direction from a particular point on the manifold. Well, we've already seen that

stack-type vectors are about rates of change of some quantity as position changes.

so you can actually think of a coordinate system as defining N stack-type vectors at every point, where N is the number of dimensions of the manifold. Just look at a piece of graph paper and you can see the stack-type vectors. Because the stack-type vectors are showing the rate of change of the coordinate, they are actually the derivative of the coordinate with respect to position (i.e. the gradient).

You can probably already see it, but something interesting happens when we combine the notion of traveling in a particular direction at a particular rate with the notion of a particular quantity (coordinate or otherwise) changing according to position. We'll talk about that next.

by jtauber : Created on March 28, 2008 : Last modified March 28, 2008 : Categories poincare_project : 0 comments (permalink)

The Rubik's Cube Can Be Solved But Is It Grammatical?

In my previous post I mentioned Joyner's paper Mathematics of the Rubik's Cube.

The phrase "The Rubik's Cube" sounds odd because you can't normally use an article with a pre-nominal genitive if the pre-nominal itself wouldn't normally take an article.

You can say "the paper", "the professor" and "the professor's paper". You can say "David's paper" but not "*the David's paper". (Although note that if talking about the sculpture "the David", you can say things like "the David's left hand". And, because of Donald Trump, you could say "the Donald's hair".)

You can't say "the Rubik" and so "the Rubik's cube" seems ungrammatical if you think about its component parts.

What's happening is, of course, that "Rubik's" isn't acting as a genitive anymore but rather "Rubik's Cube" has been reanalyzed as an opaque compound noun. It's just still written in terms of its components.

by jtauber : Created on March 27, 2008 : Last modified March 27, 2008 : Categories linguistic_observations : 3 comments (permalink)

Twenty-Five Moves Suffice

I've talked about the Rubik's Cube before and linked to last year's paper by Kunkle and Cooperman proving Twenty-Six Moves Suffice for Rubik’s Cube.

Now Tomas Rokicki has proved that Twenty-Five Moves Suffice for Rubik's Cube. Actually, what he proved is that no configuration takes 26. If x <= 26 and x != 26 then x <= 25 QED.

It is known that some configurations need 20 moves and that no configuration needs 21. So the possible optimal move maxima are 20, 22, 23, 24 and 25.

Via Dave Long, I also found out about Joyner's Mathematics of the Rubik's Cube (pdf) which became the book Adventures in Group Theory.

UPDATE: Actually, I don't think it's been proven that no configuration needs 21, just no configuration has been found that needs 21.

UPDATE 2: David Joyner informs me a 2nd edition of his book is coming out soon.

by jtauber : Created on March 27, 2008 : Last modified March 28, 2008 : Categories algorithms mathematics : 3 comments (permalink)

First to Hit 100

So I was about to blog on the fact that in the last two hours I've read about both Opera and WebKit reaching 98/100 on the Acid 3 Test and that I was wondering who would hit 100/100 first.

Then I saw this ACID3: Strike ninety-eight. Make that 100

Congratulations!

UPDATE: WebKit is the first to make it public, though. Note, neither actually pass the full test yet (which requires pixel-accuracy with a reference image).

by jtauber : Created on March 26, 2008 : Last modified March 27, 2008 : Categories web : 0 comments (permalink)

Latin Mottos on Japanese Running Shoes

The name of Japanese athletic equipment company ASICS is an acronym for the Latin phrase anima sana in corpore sano—"a sound mind in a sound body".

by jtauber : Created on March 26, 2008 : Last modified March 26, 2008 : Categories linguistic_observations : 3 comments (permalink)

Documentation Can Speed Up Your Code

I just was documenting some code that looked (roughly) like this:

def a(x, m):
    for i, o in enumerate(sorted(x)):
        if o > m:
            break
    return i

and my comment was "return how many items in x are less than or equal to m".

The very act of writing the comment made me realise the code could be rewritten as:

def a(x, m):
    return len([o for o in x if o <= m])

which is not only more succinct but runs 6-8 times faster! (UPDATE: ...on my data size -- as Sergio points out below, the two algorithms differ in complexity)

(Incidentally, the list comprehension also runs twice as fast as the equivalent using filter)

UPDATE (2008-03-26): Fascinating discussion going on in the comments :-) Although still largely orthogonal to the main point which is that I was originally trying to solve a domain-specific problem and it was only when I went to comment the code that I realised that what I was really doing was trying to find how many items in a list are less than or equal to a certain number. How best to do that is a topic for...well, I guess the comment thread :-)

by jtauber : Created on March 25, 2008 : Last modified March 26, 2008 : Categories python algorithms : 20 comments (permalink)

One-Forms Form Linear Spaces

One of the important takeaways from arrows and stacks as duals is that

Every linear space has a dual space whose elements are the linear, scalar-valued functions on the original space.

These linear, scalar-valued functions have a number of different names. They are variously called linear functionals, linear forms or, more specifically, and as we will call them, one-forms.

For our purposes, the one-forms are real-valued (because our linear spaces are real), although in quantum mechanics I think dual spaces are always made of complex-valued functions (and complex linear spaces).

Let's just quickly demonstrate that the dual space is itself a linear space:

Firstly, by virtue of the fact the one-forms are linear, we know:

  • w(kv) = k w(v)
  • w(u + v) = w(u) + w(v)

We define addition of one-forms:

  • (w+x)(v) = w(v) + x(v)

and scaling of one-forms:

  • (k w)(v) = k w(v)

We can see that one-forms do form a linear space, just by the algebraic properties of real number addition and multiplication:

  • ((w + x) + y)(v) = (w(v) + x(v)) + y(v) = w(v) + (x(v) + y(v)) = (w + (x + y))(v)
  • (w + x)(v) = w(v) + x(v) = x(v) + w(v) = (x + w)(v)
  • there is an additive identity 0 which simply maps every vector to 0.
  • for every w there is an additive inverse -w such that (w + -w)(v) = w(v) + -w(v) = w(v) - w(v) = 0 = 0(v)
  • a (w + x)(v) = a ( w(v) + x(v) ) = a w(v) + a x(v)
  • (a + b) w(v) = a w(v) + b w(v)
  • a (b w(v)) = (ab) w(v)
  • 1 w(v) = w(v)

Remember that if we view vectors in the context of a manifold as arrows, the corresponding one-forms are stacks.

In matrix algebra, column vectors and row vectors are similarly duals of one another.

In the next entry, we'll look at the relationship between one-forms and coordinate systems.

by jtauber : Created on March 23, 2008 : Last modified March 23, 2008 : Categories poincare_project : 0 comments (permalink)

Graded Reader Discussion and Code

Owing to the amount of interest I received about A New Kind of Graded Reader,

I have started a mailing list at

http://groups.google.com/group/graded-reader

and also I plan to make my code available at

http://code.google.com/p/graded-reader/

If you're interested in the idea applied to any language (not just NT Greek) please join us.

by jtauber : Created on March 22, 2008 : Last modified March 22, 2008 : Categories linguistics language_learning graded_reader : 0 comments (permalink)

Arrows and Stacks as Duals

Part of the glacial Poinaré Project.

We've introduced the notion of a linear space and seen that, in the context of a manifold, there are at least two distinct types of linear spaces:

Arrow-type linear spaces are about position on the manifold and rates of change of position. Stack-type linear spaces, on the other hand, are about rates of change of some other quantity defined on the manifold as position changes.

These two types of linear spaces have a special relationship to one another. An arrow-type vector and a stack-type vector can be multiplied together to give a quantity which has no reference to distance or direction (what is called a scalar) and which is immune to transformations that maintain the topology of the manifold. Geometrically, you can calculate this quantity by counting how many "stacks" of the stack-type vector the arrow-type vector passes through.

Because this operation of multiplying arrow-type and stack-type vectors doesn't require any additional structures and is preserved under a homeomorphism, is it more fundamental than, say, the inner (or dot) product. As we will see in the next couple of entries, though, it has a relationship to the inner product, mediated through the metric.

We can go one step further and, algebraically, think of a stack-type vector as a function that turns arrow-type vectors into scalars. In other words if V is an arrow-type linear space then a particular stack-type vector w can be thought of as a function w: V -> R. Because the stack-type vectors that apply to the arrow-type vectors in V follow the axioms of linear spaces, the following rules fall out:

  • w(kv) = k w(v)
  • w(u + v) = w(u) + w(v)

Or put more succinctly, w is a linear, real-valued function on V.

Because the linear space of stack-vectors that apply to V has a special relationship to V, it is said to be the dual of V.

It is worth noting that everything above still works if you swap arrows and stacks. In other words, you can view arrow-type vectors as linear, real-valued functions on the linear space of stack-type vectors. The dual relationship is symmetrical. In fact, the only thing that makes one "arrow-type" and the other "stack-type" is their relationship to a manifold.

You can talk about a linear space and its dual without reference to an underlying manifold on which the vectors live. For example, the n-tuple space has a dual as well. For a given linear space of n-tuples, this dual space is the space of all linear, real-valued functions on those n-tuples.

by jtauber : Created on March 22, 2008 : Last modified March 22, 2008 : Categories poincare_project : 0 comments (permalink)

Another You Me Us We Review

Forte Magazine has a review of Nelson Clemente's EP and had this to say about You Me Us We (which I composed and co-produced):

Aussie boy Nelson Clemente has been impressing blogger types for most of 2007; his ace track "You Me Us We" left a mark on many electronic music fans with its subtle throwbacks to mellow house and 80’s europop. Its gorgeous harmony, solid production and heart-tugging lyrics helped the track along in earning its title as EQ’s Song Of The Year, 2007. Nelson’s debut E.P. "6th Perception" features this pop masterpiece along with several remixes and two new tracks.

and later...

For a first E.P (three tracks, four remixes,) this is a solid start. The perfect and sublime "You Me Us We" is still the best song on here.

Emphasis mine :-)

by jtauber : Created on March 21, 2008 : Last modified March 21, 2008 : Categories music_composition record_producing_and_engineering nelson_james you_me_us_we : 2 comments (permalink)

Relatively Speaking

Special Relativity uses straightforward mathematics with mind-bending physical implications. General Relativity uses mind-bending mathematics with straightforward physical implications.

Or so I described it to someone at PyCon tonight.

by jtauber : Created on March 19, 2008 : Last modified March 19, 2008 : 2 comments (permalink)

Inconsistent Symlinks

Set up directories as follows:

drwxr-xr-x   2 jtauber  staff   68 Mar 18 17:57 A
drwxr-xr-x   3 jtauber  staff  102 Mar 18 17:58 B
lrwxr-xr-x   1 jtauber  staff    3 Mar 18 17:58 C -> B/C

Now cd into B

jtmbp:TEST jtauber$ cd B

If you try to "execute" A from here, it tells you it's a directory

jtmbp:B jtauber$ ../A
-bash: ../A: is a directory

Now go back to the top directory

jtmbp:B jtauber$ cd ..

and cd into C (the symlinked directory)

jtmbp:TEST jtauber$ cd C

If you try to execute A from here, it can't find it via "../A" only "../../A"

jtmbp:C jtauber$ ../A
-bash: ../A: No such file or directory
jtmbp:C jtauber$ ../../A
-bash: ../../A: is a directory

so the attempt at execution is based on the actual absolute path, not the path based on following the symlink.

However,

jtmbp:C jtauber$ cd ../A
jtmbp:A jtauber$ 

So cd uses the path based on following the symlink but relative paths for execution do not.

I realise this is likely because cd is shell-based (and so knows the path that was followed to get to the current directory) whereas execution is a system call (which doesn't know the path that was followed to get to the current directory) but it's interesting nevertheless (and occasionally annoying).

This is on OS X but the behaviour is the same on Linux as far as I know.

by jtauber : Created on March 18, 2008 : Last modified March 18, 2008 : Categories os_x : 7 comments (permalink)

PyCon Update

I am proud to announce that a couple of hours ago, I was elected to both membership and to the board of directors of the Python Software Foundation. Thank you to David Goodger for nominating me for membership and for encouraging me to run for the board again.

It's a nice coincidence that it happened on Pi Day.

This afternoon at PyCon I'm looking forward to some exciting Django news from Adrian.

Tonight we're running a BOF for anyone interested in mentoring Python projects in the Google Summer of Code.

Note: the last twenty minutes has been the longest I've had a working network connection since I got here :-(

UPDATE: It was actually Jacob that made the announcement. I don't want to steal his blog thunder so I won't mention it here other than to say, it's something I want to help out with :-) Very exciting!

by jtauber : Created on March 14, 2008 : Last modified March 14, 2008 : Categories python django summer_of_code pycon : 1 comment (permalink)

PyCon

On Wednesday, I'll be heading to Chicago for PyCon. I'm looking forward to catching up with people there and getting a lot of Django hacking done.

by jtauber : Created on March 11, 2008 : Last modified March 11, 2008 : Categories python django pycon : 1 comment (permalink)

I Have A Song On iTunes

I have a song on iTunes!

Previously, I've written about my song You Me Us We which was a finalist in the Unisong International Songwriting Contest and named by ElectroQueer as their Number One Song for 2007.

Well, now Nelson Clemente's debut EP 6th Perception, which features the song, is available on iTunes!

BUY THE ALBUM! Or at least buy the song :-) It's track number 3.

by jtauber : Created on March 1, 2008 : Last modified March 1, 2008 : Categories music_composition record_producing_and_engineering nelson_james itunes you_me_us_we : 4 comments (permalink)

Google Summer of Code 2008

Well, the Google Summer of Code is on again and the Python Software Foundation have asked me to coordinate for the second year (mustn't have screwed up enough last year :-)

It's early days (the organizations involved haven't even been picked yet) but if you are interested in participating in a Python project, either as a mentor or student, you should check out both the official Google page and the SummerOfCode page on the Python wiki.

You should also join the soc2008-general mailing list.

by jtauber : Created on Feb. 27, 2008 : Last modified Feb. 27, 2008 : Categories python summer_of_code : 0 comments (permalink)

Another Dictionary Trick

Continuing on from my previous post about python dictionaries.

Imagine you're using a defaultdict to count objects. That is, you set up like this:

from collections import defaultdict
counts = defaultdict(int)

and then have a bunch of these for different keys:

counts[key] += 1

Now say you want a list of all the objects in order of their count, like I did earlier this morning. My first intuition was to use

sorted(counts, key=lambda i: counts[i])

which then got me wondering if there was a way to create a function that gets an item from dictionary without using lambda—much the same way as the operator module can be used instead of lambdas in many cases.

Then I had a doh! moment. Of course there's a function that gets an item from a dictionary: the get method. And so the above can be rewritten:

sorted(counts, key=counts.get)

by jtauber : Created on Feb. 27, 2008 : Last modified Feb. 27, 2008 : Categories python : 3 comments (permalink)

Evolution of Default Dictionaries in Python

I write a lot of code where I use a dictionary of sets (or lists or counters, etc)

Method 1

dict_set = {}

if key not in dict_set:
    dict_set[key] = set()
dict_set[key].add(item)

Method 2

dict_set = {}

dict_set.setdefault(key, set()).add(item)

Method 3

from collections import defaultdict

dict_set = defaultdict(set)

dict_set[key].add(item)

setdefault was added in Python 2.0 and I've been using (and loving) it for years.

It was only a month or two ago that I discovered collections.defaultdict. Now I use it almost every day.

UPDATE: I forgot to mention that defaultdict was added in Python 2.5. And owing to the fact that int() returns 0 you can use defaultdict(int) for a dictionary of counters.

by jtauber : Created on Feb. 27, 2008 : Last modified Feb. 27, 2008 : Categories python : 9 comments (permalink)

Time Machine Isn't What It Used to Be

Yesterday, after a mammoth session importing and organizing photos in Aperture 2, Time Machine informed me that the backup drive was full.

That didn't bother me—it was inevitable—but what did disturb me was the rest of the message. It told me that the earliest backup was now February 18th. In other words, it had eliminated everything from November 19th thru February 17th.

I knew what the behaviour would be when the disk filled up but I didn't expect it to eliminate so much in one go.

I suspect that I would be more likely to want to find stuff from November to February than in the last week although maybe I'm thinking of Time Machine too much as version control rather than backup. Still, I would have preferred it to sacrifice more recent backups rather than eliminate the oldest stuff.

There is an option "Warn when old backups are deleted" in System Preferences which was checked but I'm not sure if that means "tell me when old backups have been deleted" or "tell me when old backups are about to be deleted". My recollection of the message yesterday was that it had already done the deed and there wasn't anything I could have done about it.

Either way, I wish the behaviour in this scenario had been different.

by jtauber : Created on Feb. 24, 2008 : Last modified Feb. 24, 2008 : Categories os_x : 2 comments (permalink)

Script Breakdown

This weekend, I'm trying to finish an initial breakdown of the script for In the Light of Day. As a preliminary step to scheduling and budgeting, a script breakdown means going through the script and identifying the locations, characters, props, etc, for each scene.

Because the script jumps around a bit, I'm actually distinguishing a scene as written in the script from a "story scene". I'm calling it a story scene if it's a single sequence of action in one location, even if it's non-contiguous in the script. The important point being that we almost certainly want to film a story scene in one go for continuity.

So the main relationships I'm dealing with are the many-to-one from script scene to story scene and the many-to-one from story scene to story location. (Again, I say "story location" because the same physical location may act for multiple locations in the story and I'm just focused on the locations in the story at this stage.)

Once that's done, the many-to-many relationship between characters and scenes can be added. And then from this, we can see who is needed in what locations for how long. And thus begins the process of scheduling (which I'll talk about when we get to it)

I have 98 script scenes and will report shortly on how many story scenes and story locations that corresponds to.

Incidentally, I'm doing all this in a home-grown Django app I'm building as I go along. Mostly just working in the admin console at the moment.

UPDATE (2008-02-17): After an initial pass, there are 75 story scenes and 24 story locations.

by jtauber : Created on Feb. 16, 2008 : Last modified Feb. 17, 2008 : Categories django filmmaking in_the_light_of_day : 0 comments (permalink)

A New Kind of Graded Reader

Back in 2004, I talked about algorithms for optimal vocabulary ordering. Then in 2006, I talked about using this and other techniques in teaching New Testament Greek (which I've resumed doing with this method, btw)

Earlier this year at BibleTech:2008 I briefly touched on my graded reader approach. It generated a lot of interest so I decided to record a separate presentation at home this weekend, explaining some of the ideas behind the graded reader.

After multiple failed attempts to upload it to Google Video, it's now on YouTube and embedded below. Sound was recorded and mixed in Logic Pro and then synchronized with a presentation in Keynote and output as Quicktime.

Running time is just shy of 9 minutes.

UPDATE 2008-03-22: I have started a mailing list at http://groups.google.com/group/graded-reader and also I plan to make my code available at http://code.google.com/p/graded-reader/

by jtauber : Created on Feb. 10, 2008 : Last modified March 22, 2008 : Categories linguistics speaking language_learning new_testament_greek graded_reader : 8 comments (permalink)

JMW's Strange Meeting With Romeo and Juliet

Back in the late 1980s there was a new music group in Perth called EVOS. In my final year of high school, I was involved with the EVOS Youth Ensemble as their youngest composer. I had an opportunity to have one of my pieces performed on the national classical radio station ABC FM during New Music Week when EVOS put on a concert featuring young Perth composers and performers.

One of the pieces performed that night was not composed by a local but by an obscure contemporary Hungarian composer, István Márta, that the leader of EVOS had met while studying in Hungary. The piece was entitled "JMW's Strange Meeting With Romeo and Juliet".

It was a playful piece, part minimalist, part neo-classical, part fugue with awesome time signature changes and scored for piano or harpsichord and 5 unspecified instruments. A New York Times review of the piece from the same time period described it as "a light, appealingly textured Minimalist interlude."

At various times during the last 17 years, I've wondered about getting hold of the score. About six months ago, I started looking online again and couldn't find it on any of the usual sheet music sites. I did see it on one sheet music distributor's catalogue but they didn't have any online ordering so I wrote to them. They told me they could order it especially from Hungary for me.

I'd given up on receiving it when yesterday, a package arrived containing the score. Just reading it brought back a flood of memories. But then last night, I realised about 80% of it in Logic Pro, pretty much using the instrumentation I remembered from the EVOS concert: piano, clarinet, sax, bass guitar.

When I'm finished, I'll put up an MP3 of it. I might also do a more electronic realisation of it (I'm thinking harpsichord + Moog).

UPDATE (2008-02-10): Here's an MP3 of my first realisation: piano, flute, soprano sax, clarinet, bassoon, acoustic guitar, bass guitar and percussion. Enjoy!

by jtauber : Created on Feb. 7, 2008 : Last modified Feb. 10, 2008 : Categories music : 1 comment (permalink)

Django Collaborator Wanted

Just on the off-chance I find the right match amongst the readers of this blog...

So here's the deal: I'd really like a django developer to collaborate with on Quisition, habitualist and/or one or two other sites I haven't announced yet. This isn't a paid gig (yet!), I'm looking for a partner or two. Also, and maybe this will make it more interesting for some of you: I want to make large parts of all my sites into generic open source django apps so you could view this as mostly contributing to a set of open source projects, but ones that are directed toward the needs of specific websites.

Other technologies involved are jQuery and PostgreSQL (and obviously Javascript, SQL, CSS and Python in general).

Being local (i.e. Boston area) would be preferred as I'd love time face-to-face but I'm open to remote collaboration. If we already know each other, that makes it a much easier decision.

Email me if you're interested in discussing more.

by jtauber : Created on Feb. 5, 2008 : Last modified Feb. 5, 2008 : Categories django quisition : 1 comment (permalink)

Usavich

(via Ned Batchelder)

Usavich has to be just about the strangest thing I've ever seen. And yet I'm addicted.

I can't summarize this minute-or-two-per-episode Japanese cartoon any better than Ned does:

two rabbits are imprisoned in Russian jail. One is dumb and gentle, the other is placid unless provoked, and then he becomes ultraviolent. There's also a transvestite chick and a frog, and there's no dialog.

The first episode is weird. And it gets weirder after that.

The animation technique is fascinating, mostly 2D (in a style resembling a children's book) but with the occasional shift (especially in the second season) into the third.

And the series involves the most bizarre use of Bach's Jesu, Joy of Man's Desiring I've ever heard.

Also check out the Wikipedia page on Usavich.

by jtauber : Created on Feb. 4, 2008 : Last modified Feb. 4, 2008 : 0 comments (permalink)

Statistics

Following Bob, Joe and Ryan, here are my Browser / OS stats for the last month (rounded to nearest tenth of a percent):

  Firefox    54.6%  
  Internet Explorer    24.7%  
  Safari    9.9%  
  Mozilla    6.5%  
  Opera    2.5%  

  Windows    60.3%  
  Linux    20.5%  
  Macintosh    18.3%  

(iPhone at 0.2%)

For comparison, here are the figures for the same period a year ago:

  Firefox    44.8%  
  Internet Explorer    37.1%  
  Safari    9.6%  
  Opera    3.4%  
  Mozilla    2.21%  

  Windows    69.4%  
  Macintosh    16.9%  
  Linux    12.9%  

by jtauber : Created on Jan. 30, 2008 : Last modified Jan. 30, 2008 : Categories this_site : 0 comments (permalink)

Marcie Lascher

For a while now, Marcie Lascher has been asking me to write a blog entry about her. She doesn't care what I say, she just wants to have a blog mention her so she feels more Web 2.0 enabled. But while I'm at it: Marcie, I think you are awesome!

by jtauber : Created on Jan. 22, 2008 : Last modified Jan. 22, 2008 : 3 comments (permalink)

Macworld Keynote

Lots of good stuff of great interest to me.

No wow moments during the video given rumours and spoilers beforehand, although I did like the way he announced the studios behind iTunes movie rentals, announcing the mini-majors before the majors and the latter with the line "and by the way...these six too".

I've already bought external drives for use with Time Machine and already have an Airport Extreme, so Time Capsule came a little too late for me. It is a pain unplugging the drive from my laptop all the time, though. And if I get an Air (see below) I'd need a Time Capsule anyway; unless they release an update that allows any external drive to connect to an Airport Extreme.

I've already updated my iPhone. Ability to put bookmarks on the home page is nice (currently, I have Facebook and Quisition). I've tried out the locator and it works great in my apartment. I'll try it more tonight when I'm out on the road.

Updated iTunes too and rented a movie. Worked beautifully. I will definitely be watching a lot of movies this way now.

I don't have a TV here in the US (watch everything on my computer) so Apple TV doesn't interest me at the moment. Steve's admission of failure on the first release was refreshing and it's nice that Take 2 is a free software upgrade for existing Apple TV users.

I only heard Steve say "Boom!" once (around the 45m mark). Coincidentally, it was shortly after the Flickr demo blew up.

The Air is very appealing to me. I used to have a 12" PowerBook from 2004 when I was traveling between Australia and the US a lot. My current laptop (a 17" MacBook Pro I bought mid-2006) dates from a time when I was living for months at a time in a hotel and it was basically my primary machine. Now I've settled into an apartment, I have a Mac Pro as my primary machine. The times I do travel, the 17" is just a little too big.

So the Air is a nice option as a travel laptop. The battery life is appealing. I haven't heard anything about whether the SSD increases the battery life even more. The HDD is slow but the SSD is a lot more expensive. I haven't decided yet. I'm at least going to wait a couple of weeks to see one in person and hear initial feedback.

by jtauber : Created on Jan. 16, 2008 : Last modified Jan. 16, 2008 : Categories apple mac iphone itunes : 3 comments (permalink)

Keynote Bad Request

Yet again I can't watch the Macworld Keynote Address Quicktime because of a "Bad Request" error. Has happened every year and I have to wait a day or two. What's a fanboy to do?

UPDATE: Working now.

by jtauber : Created on Jan. 15, 2008 : Last modified Jan. 15, 2008 : Categories apple : 0 comments (permalink)

Quisition User Goals for 2008

Last year my goal for