Home

Tue, Oct. 14th, 2008, 05:02 pm
If you're gonna be dumb then you gotta be tough

My constant prattling on about message queues has been going on for a while now.

Since then I've been looking long and hard at RabbitMQ and QPid, both of which look hella sexy and very, very promising.

However, at the moment both still don't quite pass my "as easy as memcached to set up test".

Given that I've been drinking with known both the Dopplr and the Flickr team for a while (and borrowed desk space off Dopplr in return for tea every morning and Pho once a week) it's not surprising that I've bent their collective ears about this more than once.

They're both big advocates of message queus - witness recent blog post from both of them. However something else that I've ranted at talked to them about is the concept of premature scaling.

There are certain semi-best practices that you can do to make web sites scale (both technically and socially). Stuff like sharding for example. Later, if you get really big you'll maybe want to internationalise. But you obviously don't want to do all that from the get go when you're only 1 person working on a VM somewhere on some shared box in a colo.

So there's a line somewhere about what you should do upfront and what you should leave till later. It's a grey area and it's different for every site but general consensus was that making sure you're not using auto incrementing primary keys on tables you might want to shard is probably the right thing but leave your i8ln till later (although you always want to keep that sort stuff in mind and gnerally structure your code to make it as easy as possible later).

Obviously, being me, messaging came up. Now there's really two types of messaging - one when you want to broadcast an event to an unknown number of listeners (let's call that PubSub) and one when really you're just using it to do asynchronous tasks (let's call that Job Queues).

PubSub very much falls into the realm of "You don't need this now" I think. Job Queues on the other hand - they can be very useful. From generating thumbnails to sending notification emails or SMSs - none of this needs to be done to render the page so you might as well shunt it off to be done later when you're not desperately scrambling to return some HTML to the user as fast as possible.

LJ uses a system called TheSchwartz (the name is actually not one but two semi-elaborate in-jokes) for this stuff. Dopplr uses ActiveMQ I believe and Flickr use their own internal system.

TheSchwartz is fantastic. It scales for a start. And it runs off a database so it's easy to set up and admin (since you already presumably have a database running your site).

Tom Insam (who works at Dopplr and is somewhat of a mad genius even if he does have girly long hair) recently pondered about having a really simple, database backed message queue that used STOMP as its interface. Then, when you got really big, you could switch over transparently to using one of the big boy queues.

"Hmm," thinks I, "I wonder how hard it would be to make a STOMP interface to TheSchwartz"

So I started hacking on a generic STOMP sever with every intention of just do a very simple layer over the top of TheSchwartz.

Then generic layer took all of, ooh, about 30 minutes to write.

What I should have done then is then write TheSchwartz specific layer which would probably have only taken another half an hour or so.

Instead I started sketching out in my head how you'd write a real proper PubSub message broker.

A couple of hours later I'd done most of it - only stopping when the dev machine I was testing on suffered a prolonged power outage.

So here we go.

This contains both the generic layer (the simple bit) and the actual broker (the tricky bit).

How it works is that a Parent server starts up and starts listening. When a new STOMP client connects it fork()s off a child which listens for new STOMP frames and reacts accordingly.

The clever bit is when a message comes in. The Child serialises the frame and sends it via a socket pair to the Parent. Then parent then sends it back down via another socket pair to all the Children. The Children then decide whether or not to send it to their Client depending on what SUBSCRIBE frames they've received.

Queues (first come, first served) are a bit more complicated than Topic (broadcast) messages though.

In that case the Parent also creates a semaphore and the Child then tests to see if their the first to decrement it. If they are then they send the message. The last Child to check removes the Semaphore.

Now, don't get me wrong - this is very, very alpha quality at the moment - I'm pretty sure the queue implementation is duff and also that it's liable to fork() bomb your machine at a moment's notice but it shouldn't be too hard to clean up.

However I doubt it will ever be Enterprise class. For a start it's all memory backed at the moment but even when I write a planned subclass that uses a DB and TheSchwartz for persistence it's just not careful enough or efficient enough to properly scale. It might still be useful for small sites though but really it's an intellectual exercise. It is incredibly simple to use though. In most cases just running
    stomp-broker --daemonize 

should be enough.

Tomorrow though, I'll finish off the far more useful STOMP interface to TheSchwartz during our weekly Hack Days and make it as easy to install and run.

The title of this post refers both to the fact that the Job Queue might be useful despite being so simple and also to the fact that I'm a dumbass for not doing the useful thing first and fiddling round with the intellectual geejaw instead.

Oh, and it's catchy Roger Alan Wade song used, appropriately, for Jackass.

Fri, Nov. 16th, 2007, 12:09 pm
You Get Me Closer To God

And ooooooooooooh, the music puns get worse and worse.

So, at work we stumbled across an interesting Perlism. Well, interesting if you're a huge nerd which, must as it pains me, I'm going to have to concede.

Anyway, so Perl has the concept of a DESTROY method which gets called on an object when it's, err, destroyed. Also, in Perl, objects can be any kind of a blessed scalar value - usually it's a hash reference but it could be a blessed array, or a bless sub routine reference. Which is where we join the story. Observe this:
my $foo = Foo->new;
$foo    = undef;

package Foo;

sub new {
    my $class = shift;
    return bless sub { print "Hello from Foo\n" }, $class; 
}
sub DESTROY {
    my $self = shift;
    $self->();
    print "Destroying Foo\n";
}
1;

We'd expect it to print
Hello from Foo
Destroying Foo

But it prints nothing.

How weird.

However if we do this (note the $class in the print statement):
my $foo = Foo->new;
$foo    = undef;

package Foo;

sub new {
    my $class = shift;
    return bless sub { print "Hello from $class\n" }, $class; 
}
sub DESTROY {
    my $self = shift;
    $self->();
    print "Destroying Foo\n";
}
1;

We get both statements printed.

Freaky, ne c'est pas?

So the reason, as far as I know is that DESTROY is only called when all references to the object are destroyed. Presumably for optimisation reasons, the anonymous subroutine in the first case is invariant and the new subroutine takes a reference to it and so the DESTROY is not called until the new goes away which it won't because the symbol table isn't wiped.

So the reason why the second one works is that by referencing the $class variable the anonymous sub is upgraded to a closure and a closure gets a new copy for every instantiation and thus gets DESTROYEDed.

It all makes sense if you squint at it askance but it's still the sort of thing that will trip you up.

Thu, Sep. 13th, 2007, 12:05 pm
With these ropes I tied can we do no wrong?

Last week I did a big refactor of some Java code, massively simplifying the flow and making things clearer, faster, more extensible and more secure. In general I'm hugely happy with it and I'm also pretty happy with my Java. It was a long time ago when I last did Java professionally and so this past year I've always been a bit wary that my code wasn't idiomatic.

Idiomatic code, like patterns, is interesting. Sometimes brevity or whatever can and ought to be sacrificed for clarity. If nothing else then idiomatic code makes the next maintainer's job easier. And that could well be you. Remember, you always code for three people - you now, you in the future and the person who comes after you. And idiomatic code tends to integrate better with with external libraries (as long as they're largely idiomatic of course). Plus, they're usually idioms for a reason.

So, the first cut at refactoring went incredibly quickly and I excised all the old baroque, rotten code that had built up as new wrinkles in underlying libraries came up and as old assumptions had been discredited and new requirements had come up. Not that the old code was bad it just needed a spring clean and a new wardrobe.

I then rebuilt the functionality in a much saner way working to a general plan in my head and filling in the details as I went along. That went incredibly quickly - I had working code by the end of the first day and had filled out the details by the end of the second day. All in all, about a 5000 line diff.

So far so good.

Then I took a step back, sketched my class diagram on a white board and started thinking about making things more idiomatic. And in Java that means Interfaces. To paraphrase The Rhyme of the Ancient Mariner - "Interfaces everywhere and all the compilers did shrink. Interfaces everywhere and not a drop to drink. Because they're doing my head in and I have a powerful thirst for some alcohol".

The debate about multiple-inheritance versus interfaces has been done to death elsewhere and by better, wiser and more scarily obsessive people than me. I've come across a few occasions when I could really have done with multiple inheritance but mostly I've been able to work around it and I can understand the arguments against it so we'll just leave it at that.

But I'm beginning to wonder if I made a mistake. Should I just have left it at the old code with the leaky abstractions? Has separating it out into interfaces tricked me into over engineering things, made me jump through conceptual hoops which, whilst correct in a very 'pure' way have actually made things worse.

A while back I was talking with someone about writing a book - "Java for Scripting Language Programmers". One of the things we talked about was the fact that programmers who are frolicking in a language which isn't their normal one will find warts that habitual users of the language never come across, in much the same way that a user can find a bug in 30 seconds that the programmer of an app hasn't come across in 6 months of testing - there's an underlying conceptual model and you instinctively steer away from doing stuff wrong "The bug happened because they tried to add a Frob to a Bleep! Why would they ever do that?!"[1]

In short I'm wondering if my issue is because I'm trying to program Java like Perl. Or I expect Java to be like Perl and then get upset when it's not.

Or maybe it's just that Bondage and Discipline languages are just annoying (although Piers Cawley once remarked "Perl let's you program in a Bondage and Discipline style ... it just lets you have safe words".

I've often thought that programming is like Architecture - it's not for nothing that we stole the concept of a pattern language off Christopher Alexander's books "The Timeless Way of Building" and "A Pattern Language . Building a whole system is like building an estate with roads and parks and shops and places to live. You need some discipline because otherwise people just swarm everywhere and it's annoying to get everywhere but, ideally, adding new functionality in the form of a new building or communal area should be an easy task with an obvious course of action.

However if the system is irritating to use you start getting ugly brown marks across the middle of your parks as people take short cuts across the grass. Sure you can then pave that path to prevent further damage but that screws up your design aesthetic and really it should have been obvious that was going to happen and the situation should have been dealt with in advance.

In short I think you should accept that your users are going to occasionally want to do stuff that you never dreamed that they'd want to do. Or that occasionally breaking the rules will be necessary and should be prepared to deal with that. Give the programmer a mechanism to do it and at least let them know what the consequences are. More than once I've had to do
    #define private public
    #include <somelibrary.h>
which is obviously bad and wrong and has horrific long term consequences. Much nicer if I could that within a tight scope in much the same way Perl allows you to do
    {
         no strict 'refs';
         *$sub_name = sub { print "Hello World\n" };
    }
In short, trust the programmer and let him, her or it have enough rope to shoot themselves in the foot if they really want to. They may have a damn good reason and it's not up to you to second guess them, only to give them a warning then let them get on their merry way when they brush you aside.

Actually, what I should be doing is finishing off this code instead of procrastinating about it on LJ. But there you go.




[1]Apparently it's not uncommon for tourists to blunder into riots happening in cities whereas natives subconciously stay away, warned off by environmental clues. A little trivia for you there. Read "Sources of Power" by Gary Klein. It's really good.

Tue, Sep. 4th, 2007, 11:28 am
Television, the drug of the nation

Que geek! That overwhelming urge to automate your life using nothing more than a rag tag collection of Perl scripts, RSS feeds, chewing gum and lollipop sticks. I'm convinced that if I had children they'd be read bedtime stories using a combination of Festival and Project Gutenberg.

Hmm, thinking about it - maybe that's why I was subjected to compulsory sterilisation by the state.

Anyway, I present tv2feed which turns a list of TV programs into an Atom feed of when they'll next be on. Shouldn't be too hard to augment it to put in season and episode number and the scour various torrent sites a day or so after and start downloading them.

Not that I'm advocating such a thing. I'm just saying. TV piracy is bad and wrong.

Wed, Apr. 26th, 2006, 01:00 pm
Continuing Calendar Domination

As part of my ongoing effort to subsume all Calendar activity in the Perl world I knocked up a Perl interface to Google's new calendar api.

It wasn't too painful - a coupld of things bit me on the arse. Trying to beat XML::Atom into doing the namespaces how I wanted was a bit painful and the return error codes from Google's RESTful API are less than helpful. Two examples ...

When first trying to add an entry it kept returning 200 OK rather than 201 Entry Added which confused the hell out of me. Eventually I figured out that it was because of their slightly odd session system. You first POST to their servers and get a 302 Temporarily Moved with a new session id in the headers. You're then supposed to redirect to that.

I mistakenly thought that LWP::UserAgent would do that for me but it appears it wasn't keeping all the necessary data around and so the add was failing. But failing with a success code (just not the right one). I'm sure there's a good reason as to why it does that but ...

So I got that working with some copy and pasted XML and tried to create my own XML using XML::Simple (I'd given up on XML::Atom::Entry temporarily). Entries were being created but they didn't have any of my data in. More head scratching and more cups of tea and I realised that I was using <event> rather than <entry> tags. So why was it accepting it? Why was it not throwing a 500 error or whatever like I'd seen it do before? And for that matter why not some more debug information in the reponse body? *seethe*

So I had everything working in a hacky sort of way and decided to move everything over to nice, sane Net::Google::Calendar::Entry objects which were sub-classes of XML::Atom::Entry. All seemed to be going well - add, list and delete all worked fine. But update started to get a 404 Not Found. WTF?

First I checked my update code but that hadn't changed since it worked (and checking out a previous revision confirmed that). Eventually I realised that I hadn't yet put any start and end times in. Adding them in made everything work again. Graaagaah! Why let me add (and provide a default start and end time) and delete but not update? And why a fricking 404 Not Found? HOW IS THAT HELPFUL? HULK SMASH!

One thing I hated about the API was this whole magic url AND username and password AND session-id hoop jumping dance. It's not quite as bad as the insane Flickr authetication dance and the API does appear to at least be better in general than that particular monstrosity but I'm beginning to wonder if all Web Services APIs suck by nature rather than bad implementation.

Still, it all seems to be working now - a _devel version is up on CPAN and I'll add some more functionality later (like recurring events, OH JOY! <sad smiley> <weeping>)

Mon, Mar. 27th, 2006, 01:00 pm
Abusing Google

[info]brad was working on Brackup and in the comments of his LJ someone mentioned that a Gmail target would be cool.

Python has had an extension that lets it access Gmail including storing files on there (using a certain amount of trickery) which someone used, along with FUSE to create a Gmail File System

Perl had no such ability to store and retrieve files simply from Gmail. Clearly this had to be rectified. Hence Net::FS::Gmail. What's nifty is that it was trivial to create it as a versioned filesystem.

From there it was a relatively minor hop skip and a jump to create Brackup::Target::Gmail. Now if only Brad would write the restore bit of Brackup so I could test it ...

I'm now pondering a Filesys::Virtual backend. Because it's nice to be doing some hacking, ANY hacking, again.

Thu, Dec. 8th, 2005, 12:10 pm
On Python. And Perl.

Note to future self. I've been doing a lot of Python recently. True it's been on a fairly crack fuelled distributed rendering type affair and it's under 2.2 rather than 2.4 but ... there are many things to hate about it. Like the Lack of CPAN. and the weird scoping. And the indentation which bothers me more than I thought it would but for reasons other than I predicted - I still find the white space indentation hard to do mental scoping with but not as badly as I feared but I find the unhelpful error message when you mix space and tabs to be be annoying.

Actually I loathe the, to me at least, unhelpful and down right incomprehensible error messages in general although I concede that it's probably just that I'm more used to Perl's. The scoping seems batshit. The sort() in place bothers me almost as much as Perl's chomp() in place even though I understand the reason for both.

I find the docs suck. I bemoan the lack of CPAN. I can reel off a list of 20 things I hate about it.

But, of course, I can do 100 for Perl because I know it better.

And you know what - there's no difference between them. No practical difference anyway. No real compelling one. Sure the PyObC bindings are better than CamelBones but I'll care about that when I never buy a Mac. Apparently the GUI bindings are better. But the Database bindings lag far behind Perl. Po-tay-toe, Po-tah-toe. There are niches. This will always be the case.

As mentioned elsewhere the major difference between the two (aside from individual programmer familiarity) is the community. I shall leave that as an unqualified statement.

As an aside, I read this yesterday though :

"Another thing to notice is the little slam against Perl. How did Perl get involved in this? Da Silva was discussing Awk, not Perl. But the comp.lang.lisp folks can't stop talking about Perl. They are constantly talking about Perl. I looked into comp.lang.python to see if it was similar, and I found out that people in comp.lang.python hardly ever discuss Perl. I think that shows that comp.lang.lisp is sick and comp.lang.python is healthy: the Lisp folks are interested in Perl, and the Python folks are interested in Python."

Wed, Dec. 7th, 2005, 12:10 pm
talks.perl.org

I also had the idea for talks.perl.org where people could upload all their slides and notes from wherever they gave them. They could be viewed by author, date, keywords (or 'tags' in Web2.0 parlance), event, format etc etc all with a licence attached to them (such as "This talk may only be given by me", "This talk may be given by someone else as long as they don't change it" etc etc)

Of course I can't be arsed to do it, not at the moment, and for some reasons I suspect nobody else will get round to it.

Wed, Nov. 30th, 2005, 12:10 pm
Replicating that "Holy Shit!" moment

As mentioned before I got into programming by playing round with the BBC Micros at school. I vividly remember the first time someone showed me how to do

    10 PRINT "Hello World!"
    20 GOTO 10

and the screen filled up with "Hello World!". And you could put a semi-colon at the end of the PRINT statement to get it to fill the screen horizontally as well! And I did that! I made the machine do something! The machine is my BITCH!

(ObAside: as a 6 year old I was unlikely to use the words "shit" or "bitch" but you get my meaning)

As many have lamented we just don't have computers that boot straight into a programming environment. Although Windows might still have QBasic knocking around and Macs will be able to drop to the shell and thus have access to Perl, Python, Bash and, god forbid C, Objective-C and C++ this is not the same thing.

I'm convinced that it was this access to an easy hacking environment that allows Britain to punch way above its weight in the world programming stakes (although it doesn't explain why so many mad, cool hackers are Swedish and Finnish).

So how could we replicate this sort of environment? I was pondering this over a lunchtime sandwich and thought about a really cheap appliance-esque computer like Nicholas Negroponte's 100 dollar laptop or maybe have it run under a games console (the Xbox 360 with its USB and keyboard and Harddrive would seem ideal).

It would boot almost immediately into a pseudo-IDE. The language would have the normal constructs like if, while etc etc - probably AND in favour of &&. It would have scalars like Perl's and interpolation as well as lists/arrays and hashes (dictionaries for the Pythonistas). There would be no memory management. I'm undecided whether all types would be first class objects or not.

The language would be interpreted and the IDE would support halt-and-resume and a really good debugger like Visual Studio but much much simpler. It would have powerful (but probably not exposed) reflection capabilities so that a really good refactoring browser, source highlighter and auto-completion (with inline help and docs) could be supported. A 'play' button would start interpreting the language immediately. It would be a minimal amount of key strokes to get a "Hello world!" running.

I imagine a list of projects (the current running code could be saved into a project so that the overhead to start coding would be minimal) which consist of assets (being source code and graphics, movies, sound etc etc). Assets in a project would automatically have seamless version control.

It should be easy to write games in.

It should be easy to distribute the games to your friends - either through a central web site or 'beamed' somehow. In fact it would be cool if projects were also extensions/modules/libraries so when you got a friend's game through you also got all his (or her) source code but you could seperate out common functionality into modules and use that in your other games. Or download them from somewhere.

The standard libraries would be available as projects so you could use them and delve into them.

It would come with a number of games that act as a tutorial - much like I remember my teachers 'tricking' us into programming by showing us how to use Logo. Or how when you used Big-Trak you didn't realise you were doing a crude form of programming.

Of course this gets filed in the big drawer marked "Grandiose and Idealistic projects that I'll never get round to doing" but heh-ho.

Wed, Nov. 30th, 2005, 12:00 pm
The little things please me

I fiddled with the teetering morass of crack that is the Perl than runs this diary and made it so that you can got to /dev/diary as well as dev_diary.

Of no use to anyone but it was annoying me that I couldn't do it.

Thu, Sep. 22nd, 2005, 01:40 pm
Speaking of Behemoths

Little known fact - Module::Pluggable grew out of an article I was writing for Perl.com about why some code needn't go into modules and should just be copied and pasted. Of course now it's a burgeoning monstrosity because it fell foul of feature creep and ... euuch. It's horrible.

Fortunately Mark Fowler has stepped up and, in the quest to make Module::Pluggable work with PAR has refactored the whole thing massively and documented some of the design descisions. Maybe when he's done I can bung in the immediate instantiation which Module::Pluggable::Fast has and maybe they can kill that once and for all.

Bitter about people forking my code without asking - me? No!

Mon, Aug. 22nd, 2005, 01:00 pm
Graphs - OR - CPAN, CPAN, rah, rah rah

One of the ever more infrequent articles on CPAN to go up recently was this one to do with .ics files and graphing. Interesting enough as it was it also thoroughly failed to use CPAN.

I sort of see the point of teaching people how to do something (in this case glueing disparate data sources together, something Perl is very good at) even when there exists other solutions - after all I learnt network programming by writing an SMTP client and an HTTP client and then referring back to Net::SMTP and LWP::UserAgent - but I think he should have at least mentioned what was out there. And what the limitations of his code was. Maybe I'm being picky.

Either way - I went and wrote a script that used CPAN modules to do the same thing. The results can be seen here.

I really ought to turn that into GraphViz::Ics or something I suppose.

Fri, Aug. 5th, 2005, 01:10 pm
Data::ICal

Perl is weird. I mean, I know a lot of people think that it's weird full stop but sometimes it really suffers from the opensource malaise - the glaring holes in functionality that everyone knows about but no-one seems to want to fix -PGP is a particular favourite of mine. SOAP::Lite seems to be another massive bug bear. For ages, until the DateTime suite of modules came along, dates and, err, times were like that. I could go on.

ICalendar used to be like that. There was Reefknot - a sort of attempt to do calendaring stuff in Perl which produced Net::ICal and Text::vFile which sort of read .ics files. But, to be frank, they were all shit.

The mighty Richard Clamp did Text::vFile::asData which parsed a file into a loose data structure but it wasn't until Jesse 'RT' Vincent mentioned to me that he'd been writing Data::ICal which had a proper object model and a handy as_string method that things began looking up. But Data::ICal couldn't parse. Which sort of sucked.

Clearly the only avenue open for a good open source citizen was to weave together Text::vFile::asData and Data::ICal which LO! I did. And sorted out their timezone support. And even added tests because I'm attempting to be angelic in a test-driven kind of way. So now Perl has a sensible, easy to use ICalendar module can which round trip an .ics file. HUZZAH!.

Thu, Jun. 16th, 2005, 01:10 pm
Pel Mel

At someone else's behest at work I spent a couple of days writing something called Pel::Mel. Basically it acted as a bridge between Perl and MEL, the Maya Embedded Language. The advantages of this are huge - you get support for namespaces and CPAN within MEL and we can do a much better job centrally installing and versioning extensions. The way it works is quite, well, evil.

Essentially it opens a port to Maya and speaks through that. Callbacks are done by recognising a callback being apssed in, stashing it somewhere and then installing a global callback in Maya space that actually writes to a FIFO which the Pel runloop then picks up and demarshalls back into arguments for the actual callback.

I know. I was vageuly surprised when it worked too.

What it does mean is that you can write stuff like ...

    my $pel = Pel::Mel->new( port => $port );
    
    my $win = $pel->window( -vis => 1, -title => 'myWin64'  );
    $pel->rowColumnLayout( -numberOfColumns => 4 );
    for (1..64)  {
          $pel->button(-label => $_, -command => [\&foo,$_,"second call back"] );
    }
    $pel->button(-label => "quit", -command => [\&foo,"quit"] );
    $pel->window(-edit, -width => 400, -height => 428, $win);
    $pel->run;    
    sub foo {
        my $data = shift;
        my $next = shift;
        if ("quit" eq $data) {
            $pel->DESTROY;
        } else {
            print "callback from perl $data\n";
            print "second argument to call back - '$next'\n" 
                    if defined $next;
            print "\n";
        }
    }

and

    my $url  = "http://news.bbc.co.uk/rss/newsonline_uk_edition/front_page/rss.xml";
    my $feed = get($url);
    my $rss  = XML::RSS->new; $rss->parse($feed); 
    my $text = "";
    foreach my $item (@{$rss->{"items"}}) 
    {
        my $title = $item->{title};
        $title =~ s/[^\w ]/ /g;
        $text .= $title . "; ";
        last if length($text) > 255;
    }
    $text =~ s/; $//;
    my $groupname = $pel->group(-n => "Text_foo0", -em);
    my $string    = $pel->textCurves(-ch => 0, 
                                     -f  => "Courier", 
                                     -t  => quote_arg($text), 
                                     -n  => $groupname);
    $pel->setAttr(${string}.".translateX => 0);                                                  
    $pel->setAttr(${string}.".translateY => 0);                                                  
    $pel->setAttr(${string}.".translateZ => 0);  
    $pel->setAttr(${string}.".rotateX" => 0);                                                     
    $pel->setAttr(${string}.".rotateY" => 0);                                                     
    $pel->setAttr(${string}.".rotateZ" => 0);                                                     
    my $off = 0;
    while (1) {
        $pel->setAttr(${string}.".translateX" => -$off);  
        $off = (++$off%200);
        select(undef, undef, undef, 1/$FPS);
    }          
           

The last one gets the BBC news headlines and scrolls them through a scene. It's funny loading it into existing scenes and seeing letters float behind characters' heads.

Wed, Nov. 17th, 2004, 12:10 pm
Parse::CPAN::Modlist

I recently tidied up various bits of my website and collated all the various hacks in to Perl and C/C++ sections. During this I found a quick script I wrote ages ago called cpanquery which did a fast local search against the 03modlist.data.gz file. To be honest this was back when a higher percentage of modules were in the module list but it was pretty neat and (if available) used Term::ANSIColor to highlight which modules were already installed. But the cody was pretty gnarly.

So, since I was bored at work I hacked up Parse::CPAN::Modlist to finish off the suite started by Parse::CPAN::Packages and Parse::CPAN::Authors. And it was fairly easy. So now cpanquery works again and isn't quite as embarassing.

However it would be nice to have a Parse::CPAN module that wrapped up those three modules into a super ur-module. Not that I've got much use for it but the completist in me would quite like to get it done.

Wed, Nov. 17th, 2004, 12:00 pm
Buscador and Email::*

Simon (the other, other Simon) started the Perl Email Project and I got involved. I'd been noodling with an email search engine but he actually did something so I donated my Siesta trended name and then started to patch it. A lot. And then took it over because as much as I hate finishing things he hates it even more than me.

Then he quit doing Perl work and distributed his moudles amongst the masses and Casey and I took over the Email::* stuff. I'd been waiting on Simon accepting some patches to Email::Simple and Email::Store before releasing and now I had to wait for us to get the current modules reimported into some other version control system. Which has now (eventually) happened. But I've lost momentum. Which is bad.

Consider this a public reminder to myself to get my arse in gear.