Posts by sil.

Not blocking the UI in tight JavaScript loops

Everyone’s written a JavaScript loop that just loops over all the {LIs, links, divs} on a page*, and it’s pretty standard. Something like

var lis = document.getElementsByTagName("li");
for (var i=0; i<lis.length; i++) { // yes this could be more efficient, don't care
  // do something here to lis[i]
};

or, if you’re using jQuery:

$("li").each(function() {
  // do something here to this
});

This is problematic if there are, say, 2000 LI elements on the page, and what you’re doing in the loop is semi-intensive (imagine you’re creating a couple of extra elements to append to each of those LIs, or something like that). The reason this is a problem is that JavaScript is single-threaded. A tight loop like this hangs the browser until it’s finished, you get the “this script has been running for a long time” dialog, and the user interface doesn’t update while you’re in this kind of loop. You might think: aha, this will take a long time, so I’ll have some sort of a progress monitor thing:

var lis = document.getElementsByTagName("li");
for (var i=0; i<lis.length; i++) { // yes this could be more efficient, don't care
  // do something here to lis[i]
  progressMonitor.innerHTML = "processing list item " + i; // fail
};

but that doesn’t work. What happens is that the browser freezes until the loop finishes. Annoying, but there it is.

One approach to getting around this is with timeouts rather than a for loop.

var lis = document.getElementsByTagName("li");
var counter = 0;
function doWork() {
  // do something here to lis[i]
  counter += 1;
  progressMonitor.innerHTML = "processing list item " + counter;
  if (counter < lis.length) {
    setTimeout(doWork, 1);
  }
};
setTimeout(doWork, 1);

so you move the bit of work you need to do into a function, and that function re-schedules itself repeatedly, using setTimeout. This time, your user interface will indeed update, and your progress monitor will show where you’re up to. There are a couple of caveats with this: it’ll take a bit longer, and you’re no longer guaranteed to have things processed in the order you expect, but they’re minor issues.

For doing this in jQuery, a tiny plugin:

jQuery.eachCallback = function(arr, process, callback) {
    var cnt = 0;
    function work() {
        var item = arr[cnt];
        process.apply(item);
        callback.apply(item, [cnt]);
        cnt += 1;
        if (cnt < arr.length) {
            setTimeout(work, 1);
        }
    }
    setTimeout(work, 1);
};
jQuery.fn.eachCallback = function(process, callback) {
    var cnt = 0;
    var jq = this;
    function work() {
        var item = jq.get(cnt);
        process.apply(item);
        callback.apply(item, [cnt]);
        cnt += 1;
        if (cnt < jq.length) {
            setTimeout(work, 1);
        }
    }
    setTimeout(work, 1);
};

and now you can do

$.eachCallback(someArray, function() {
  // "this" is the array item, just like $.each
}, function(loopcount) {
  // here you get to do some UI updating
  // loopcount is how far into the loop you are
});

$("li").eachCallback(function() {
  // do something to this
}, function(loopcount) {
  // update the UI
});

Not always a useful technique, but when you need it, you need it.

Why not to use domain sockets for a desktop CouchDB

The obvious idea that pops into everyone’s head, including mine, when talking about having a running CouchDB that’s specific to me is: why use TCP for it? Why not just use a unix domain socket? Then you don’t have to worry about other people on the same machine trying to access it. Everyone thinks this, and on balance it’s not the way to go. This is why.

  1. You can’t browse to a unix domain socket in your web browser. This, by itself, is enough to kill the idea for me. I genuinely love the idea that applications store their data and then I can see that data in my browser using Futon, the CouchDB web UI. I can edit that data. That’s fantastic. Using unix sockets would break that.
  2. One other nice thing about CouchDB is that you can do replication between two different databases; I like this because I can have the same data on my laptop and my netbook if I want. That doesn’t work if you use domain sockets, because the two CouchDBs can’t see one another.
  3. As far as I can tell, Mochiweb, the underlying Erlang HTTP library that Couch uses, doesn’t do domain sockets anyway. (Obviously fixing this is only a Small Matter Of Programming.)

This has been a public service broadcast on behalf of the Write These Reasons Down So I Have Them To Hand Next Time Someone Suggests Unix Domain Sockets party.

Using CouchDB to store contacts

One of the things I’m looking at is using CouchDB to store data for applications on your desktop as part of the desktop data/settings idea that Rodrigo’s already written about. Obviously one of the great things here is that applications can collaborate on data stored in there; obviously one of the pre-requisites for collaboration is that everyone’s speaking the same language! So various people working on a number of different mail clients for the Linux desktop and so on are working out what the schema for contact records in CouchDB should look like.

Being able to browse around your database with a web browser is dead handy for writing this sort of thing, I have to say :-)

At the moment, this is the sort of direction we’re heading in. A CouchDB document is JSON, and an example contact looks like this:

{
   "_id": "362cbeae5f408d6863bb70892d5ba345",
   "_rev": "1-182987891",

   "record_type": "http://example.com/contact-record",
   "record_type_version": "1.0",

   "first_name": "Joshua",
   "last_name": "Molby",
   "birth_date": "1945-07-04",

   "addresses": {
       "85cf156f-fcf6-4901-9201-82ee90859213": {
           "city": "Bedford",
           "state": "",
           "description": "home",
           "country": "Scotland",
           "postalcode": "cw12 3hi",
           "address1": "Nicol Street",
           "address2": "",
           "pobox": ""
       },
       "d20f7364-e80b-47a2-a7e7-0677cb293745": {
           "city": "Bedford",
           "state": "",
           "description": "work",
           "country": "England",
           "postalcode": "dk12 3av",
           "address1": "Rush Street",
           "address2": "",
           "pobox": ""
       }
   },
   "phone_numbers": {
       "f0bac2a0-83a3-46f9-b079-d41533b87391": {
           "priority": 0,
           "number": "+84 63 6220 9178",
           "description": "work"
       },
       "cf01fc9c-703b-4ae4-b303-fcc6f8ce5a53": {
           "priority": 0,
           "number": "+91 99 6920 2837",
           "description": "home"
       },
       "f0c05bf4-de4a-48f2-bbaf-f9698e52d491": {
           "priority": 0,
           "number": "+97 52 9211 6455",
           "description": "other"
       }
   },
   "email_addresses": {
       "6e3178d8-fee6-45b1-b95a-2c76be090e2b": {
           "description": "home",
           "address": "Joshua1.Molby@uck.com"
       },
       "adb1fc2a-0468-4deb-bb6c-974db23ef7fd": {
           "description": "work",
           "address": "Joshua1.Molby@vkc.com"
       }
   },
   "application_annotations": {
       "Funambol": {
             "jobTitle": "Director",
             "company": "ACME Ltd"
       }
   }
}

Fields in this are as follows:

CouchDB fields
_id
Unique document ID, provided by CouchDB (or you can choose it explicitly if you want)
_rev
revision number for this document. Managed by CouchDB.
Contact schema fields
The contact schema is the list of fields that are stored for a contact. Since this is a shared schema, everyone can rely on it. Fields that aren’t in this list can be stored by applications in application_annotations, if an application cares about extra stuff.
  • first_name (string)
  • last_name (string)
  • birth_date (string, “YYYY-MM-DD”)
  • addresses (MergeableSet of “address” dictionaries)
    • city (string)
    • address1 (string)
    • address2 (string)
    • pobox (string)
    • state (string)
    • country (string)
    • postalcode (string)
    • description (string, e.g., “Home”)
  • email_addresses (MergeableSet of “emailaddress” dictionaries)
    • address (string),
    • description (string)
  • phone_numbers (MergeableSet of “phone number” dictionaries)
    • number (string)
    • description (string)
Basic “record schema” fields
The record schema is the basic format we’re talking about for storing any data in CouchDB; it’s a couple of fields that are in every record that everyone can rely on.
record_type
A URL which is a unique identifier for this type of record. It would be good if that URL had a page at it describing the record schema, but (importantly) this is not a reference to some sort of JSON DTD or anything
record_type_version
Version of this record type schema (so you can make updated versions if you want to make changes to field names, etc)
application_annotations
The application_annotations section of the document is where apps put their own data that isn’t part of the schema. For example, Funambol knows about “company” for a contact, but the contact schema doesn’t directly include that field. So Funambol stores it on the contact record in a Funambol-specific section, so it can happily get it back later. If it turns out that everyone’s storing their own version of the same field, then that field is probably a good candidate for being in the schema (making this sort of change is what the record_type_version field is for :))

Quick script to drop contacts in this schema into a CouchDB database: createCouchContacts.py. Requires python-couchdb (and Couch, obviously).

Filmage

So, me & Bill are making a film. It’s going to be along the same sort of lines as http://www.bbsdocumentary.com/. The plan at the moment is to document how we came to be interested in all things Internet and computers in general, and then move on to document our momentous trip to http://www.har2009.nl.

I’m under strict instructions that I’m not allowed to help with the soundtrack because my music tastes suck. The experience of thinking about a script gives you a new appreciation for the work that scriptwriters do, though. Just thinking of how it all fits together is hard. Me, personally, I’d like it to feel like a Top Gear film (it won’t look like it, since they have the best camera work in the industry, but it might have the same sort of atmosphere, if we’re really really good).

Didn’t I see something about a script-writing program for Linux somewhere? At the moment we’re using a Google document…

Working with CouchDB

I’ve been working with CouchDB as a database in which applications can store their data; there’s an increasing trend recently for applications to start using databases to store their data rather than flat files, and I personally think it’s a jolly good trend. There’s been rumours for years about the idea of a database-backed filesystem, where instead of pathnames you use queries and so on; that’s never happened (and I’m not convinced it will ever happen), but individual apps can get most of the benefits of that by using a database to store their data. I like CouchDB for this because it has a number of advantages over simple databases like SQLite; for example, CouchDB does replication, meaning that I can get all my data on all my machines. This is a genuinely lovely property. It’s been really interesting talking to the Tomboy team about how this sort of procedure ties in with what they’re doing; we’ve been working on their Snowy server and talking about its API and how it should work, too. Cool times ahead for this stuff. I’m really excited!

Ubuntu One beta

Cool, the first bit of Ubuntu One is released, which is the project I’ve been working on since I started at Canonical. We’re currently in a beta test for the file sharing part of U1; I haven’t been working on that much, but the team who have are some cool guys. You can sign up for an invite at ubuntuone.com.

I’m looking forward to more stuff happening. I was interviewed along with Matt Griffin by the Ubuntu UK podcast guys last night about the project and what we’ve done so far (and they’ve got invites to give away, too). I’m also speaking about Ubuntu One at OSCON, and the abstract for my talk seems to be being passed around as information about what might be coming up in the future :-) Cool times ahead, especially since today I came a step closer to achieving enlightenment with lazr.restful, one of the libraries I’m using.

Absolute beginners guide to Google Maps JavaScript

A mate of mine has been building a relatively complex website for Potton, the town he lives in. In six months he’s gone from knowing nothing about Django or JavaScript to building something pretty cool with lots of Google maps and so on, and he’s started a series writing up what he’s learned for other people in the same position. First essay, an Absolute beginners guide to Google Maps JavaScript.

Games in pure SVG

In the “stupid experiments” category…

If you’ve got nothing better to do for three hours in an evening, why not experiment a bit with SVG? That’s what I thought, earlier on this evening.

So: cave.svg, a game for people with no graphics criticism ability and only one finger. One single SVG file, with all the controlling JavaScript therein. Inspired by SFCave, a game I played a million jillion years ago on a Palm IIIx and which I was astounded to discover has a website and a Java version and everything.

I have discovered the following things about SVG this evening.

  1. It is dog slow. I mean, slo-o-o-o-o-o-o-ow. You’ve-finished-the-exam-and-there’s-still-an-hour-to-go slow. Sitting in a traffic jam for three hours and the kids keep asking for an ice cream slow.
  2. It works in Firefox and Opera. I’ve tested in Midori, which is a WebKit browser, and it seems to work there too except that the fonts display as black-on-black, which means that either (a) Midori misimplents the spec (10% chance) or (b) I’m doing something wrong (90% chance). It’s probably broken the same way in Safari too, but the game seems to work.
  3. You have to care about XML at inopportune moments. I spent twenty minutes trying to work out why createElement didn’t work before sighing and using createElementNS.
  4. You can specify all the sizes in percentages! So it works at any size at all and the browser handles it all for you! Resize the game while you’re playing and it all still carries on working and scales for you! Do that with canvas!
  5. The previous point appears to be the only thing where SVG scores over canvas. For everything else using SVG on the web seems rather like having your scrotum gently resting between a pit bull’s teeth. It makes everything slightly more awkward than it ought to be… and any moment now you know the pain is coming.
  6. Did I mention slow? Can somebody please tell me what kind of a world we live in where my dual-core 2×2GHz PC can’t render a screen made out of rectangles at more than 10fps without dropping keypress events? I mean, come on.
  7. It’s not very optimised code (but it shouldn’t need to be). It would probably be a lot faster if I actually did things an SVGish way, by which I mean use the transform attribute and so on, but there are so many things I’d rather do than matrix arithmetic that it’s not even funny. Up to and including eating a pound of fish fingers with broken glass in.

In my head for a while has been a slight disappointment that everyone writing games or graphics things using JavaScript has gone for canvas (which is one step away from being a plugin — it gives you a white box and you draw in it) rather than the more web-ish SVG (which works like HTML and can be intermixed and everything). I am no longer disappointed. People don’t avoid dynamic SVG on the web because they’re wrong. People avoid dynamic SVG on the web because it’s quite shit.

LugRadio Live 2009

http://www.lugradio.org/live/2009/

Auto-discoverable local websites

Epiphany, the Gnome web browser, has a nice feature where it will automatically discover websites on your local network and add them to your bookmarks list. It occurred to me that this would be useful for a workshop I’m running later this week; have some materials in a website, and then everyone at the workshop will just have it appear in their bookmarks. Well, they will if they’re using Epiphany, or Konqueror, and (since most of them will likely be Mac people) they will in Safari as well (I think).

So, I thought: I want a piece of that action. I want to create such a website and have Safari etc pick it up. But how do you do that? Ross Burton to the rescue; Ross explains how to advertise a website over Zeroconf (Bonjour for Mac people, but it’s all the same technology). So, just drop a file in that /etc/avahi/services folder and it all works.

And then I thought: how do I test it works? (I don’t use Epiphany, I use Firefox.) BonjourFoxy to the rescue too; it browses the local network for websites that are so advertised and displays them in a sidebar; works for all platforms.

So, this oughta work. (People with both Macs and Ubuntu; I’d appreciate it if you could use Ross’s docs to advertise a local webpage with a specific path on the Ubuntu box and then see if Safari on the Mac picks it up.)

Photographing the police now illegal

Unbelieveable. Photographing a police officer may now be unlawful in the UK.

…a new law – Section 76 of the Counter Terrorism Act – which has come into force…permits the arrest of anyone found “eliciting, publishing or communicating information” relating to members of the armed forces, intelligence services and police officers, which is “likely to be useful to a person committing or preparing an act of terrorism”. That means anyone taking a picture of one of those people could face a fine or a prison sentence of up to 10 years…

If this was a picture of a policeman beating an innocent newspaper vendor then it would be unlawful. Since it's just you, Joe Public, they can take all the pictures they want.

Met police “anti-terror” poster campaign

The Metropolitan police in London have unveiled a pernicious, paranoid new poster campaign encouraging Londoners to report their neighbours for doing things which “look suspicious”. Boing Boing skewers this Fatherland-like approach pretty effectively, and have run a poster remix campaign to encourage people to remix the posters with some more appropriate messaging. Now you can do the same with the greatest of ease, through the “Make your own Metropolitan Police terrorism poster” site.

Publishing screenshots and files quickly

I’ve just looked at Skitch after someone used it to share a screenshot with me, and thoughts floated across my head about how I might use that too. Then I thought, now, hang on a second, I already have a website to publish images on, but I have to save them, then scp them up, and so on, and that’s fiddly and annoying. Then I thought, this could be easier.

So, Places > Connect to Server, and fill in SSH details for kryogenix.org, with the folder being my “random” folder on the website, and tick “add bookmark” with the bookmark name being “kryogenix random folder”. Now, to take a screenshot and publish it, I just hit Print Screen (which takes a screenshot and offers to save it), say “Save”, and pick “kryogenix random folder” from the drop-down list of where to save it to. Publishing screenshots with three clicks. That’ll do nicely.

(Skitch does other stuff, as I understand it, like cropping images and adding annotations. It would be cool if the Gnome screenshot tool allowed these things too, but I can live without them.)

Python ur-developer

In response to the deep psychological case-study that is “Beards of Python“, I present the Python ur-developer, which is what you get if you average them all together. Next time you find yourself annoyed that urlparse doesn’t handle daap:// URLs properly, or find yourself thankful that Python 3.0 is fixing some of your problems, this is the guy to blame or buy beer for. Which of your friends does he most look like?

Python ur-developer

It’s a small world after all

So, there I was in the pub in Dublin, attending OSS Barcamp. Enjoying a beer or six (including Coopers Sparkling Ale, at Jan Schmidt’s recommendation, which bills itself as “the ale by which all others should be measured”, which is frankly a bit of a reach), and chatting to lots of people. The question “is this your first time in Dublin?” came up a lot, and since it is my first time in Dublin, the question got a nod and “but I’ve spent a lot of time in Cork”, because that’s where my family’s from. Mostly it gets the nod-and-smile I’m-not-really-interested reaction, unsurprisingly, and then we get into an argument about emacs or something.

One chap, though, said: oh, really? I’m from near Cork. Where exactly?

Fermoy, says I.

You’re kidding! comes the response. This chap grew up there, it turns out. And not only that, but…he knows well my cousins Ricky and Ted and Sean, Sean is his sister’s landlord, and his mum plays bridge with my great-aunt Annette.

My dad’s always said that I couldn’t walk 100 yards down the high street in Fermoy without running into someone I was related to. I didn’t realise the six-degrees-of-friendship thing would extend as far as pubs in Dublin.

It’s a small world after all.

Music and movies on the TV

I have a reasonably large collection of music and movies. In my lounge, there’s a big computer with a 1TB drive in it, which is where all the movies and music live. It’s running MythTV, and plugged into the television. Upstairs, there’s a second MythTV box, a front-end only, which I use for watching TV in bed. My laptop runs Banshee, and can see the music and films through gvfs and SSH to the main MythTV box.

This all works fine. But it’s annoying. I don’t really like MythTV’s interface much. Creating playlists in Banshee is great and easy, but those playlists don’t appear in MythTV. I have to import new music twice, once into Banshee and once into Myth. I want to be able to do it all from one place, and have it all work.

So: what should I do? I’m happy to change almost everything about the setup, with the one hard-and-fast requirement that every component needs to run on Ubuntu, and I’d much rather run stuff that’s packaged for Ubuntu. I’d prefer to use Gnome apps and GStreamer apps where possible, but if I have to step away from that I’ll think about it.

I’ve had various thoughts about this; I don’t know whether any of these are realistic, and I’d happily hear your thoughts on any of these or on anything else that I haven’t mentioned:

  1. Make MythTV a UPnP server, keep Myth on the main machine and the upstairs frontend, and use a UPnP client on my laptop. Flaws with this: I don’t know whether UPnP does playlists, I don’t know whether you can edit a playlist over UPnP, Banshee doesn’t have UPnP support afaik, Rhythmbox does but doesn’t play videos.
  2. Investigate the mythtv:// source in GStreamer and build a Banshee plugin for it. Downside: I’m not very good with Mono stuff, so writing a Banshee plugin is hard. Rhythmbox would be easier (I’m fine with Python), but again, Rhythmbox doesn’t do videos
  3. Use Elisa on the server instead of MythTV. Flaws: not sure how this helps the edit-playlists-on-my-laptop problem; see above issues about UPnP; Elisa doesn’t actually work very well, or it didn’t last time I tried it (it was very slow, and the UI is slickish but doesn’t actually seem much easier than Myth); Elisa doesn’t record stuff off DVB (although I could keep mythbackend running, but how would I configure it?)
  4. something else I haven’t thought of

Lazyweb, tell me what to do…

Roman dates in Wordpress

In honour of Tom’s migration from Blosxom to Wordpress (thus joining the rest of us here in the twenty-first century), and in recognition of how I owe him a present and all, I’ve decided to alleviate his pain.

You see, because Tom’s a nutcase, he had all the dates displayed on his previous Blosxom weblog in the Latin form, using a Perl program to convert dates to Roman that he developed. Clever and elegant. Pointless, natch, but he seemed to enjoy it. However, the move to Wordpress has broken that, because Wordpress isn’t written in Perl, it’s written in PHP. So Perl plugins don’t work for it.

So, I have taken it upon myself to convert his Perl Roman date converter to a Wordpress PHP plugin. Download the Wordpress Roman Dates plugin here. Install by dropping into your wp-content/plugins folder and naming it romandates.php.

Nota bene primus (since we’re doing Latin stuff): this isn’t very idiomatic PHP; it’s a direct conversion from the (not very idiomatic either) Perl original
Nota bene secundus: this would have been impossible for anyone who wasn’t me, because Tom didn’t actually publish the source of his Perl program. But I’m his sysadmin, heh heh heh.

Updates on the “ARIA stylesheet” hack

My ARIA “stylesheet” hack came up on the WAI-XTech mailing list. Some of my commenters here, and some of the people on the list, seem to have misapprehended what the proposal was designed to do; I’ve mailed the list, but it seems useful to post these clarifications here too.

  1. I am not proposing adding ARIA to CSS. An “ARIA stylesheet” looks like a CSS stylesheet because that’s a convenient way to apply properties to elements, but they aren’t the same thing.
  2. I’m not proposing that the technique requires JavaScript. My suggestion is that browsers natively understand how to retrieve an “ARIA stylesheet” and apply the ARIA attributes defined therein to
    elements, as per the selectors in the “stylesheet”. The JavaScript implementation was just to demonstrate how it would work, and a prototype for how people might support older browsers which don’t have this native “ARIA parsing”, in the same way that there are JavaScript libraries which mimic HTML5 WebForms handling for older browsers that don’t yet support <input type="range">.
  3. The “ARIA stylesheet” only dictates the initial setup of a page, in much the same way that a CSS stylesheet does for presentation. If I use JavaScript to alter the style of an element, that change is not
    reflected in the CSS stylesheet text, but it is obtainable through element.style or getComputedStyle(). In the same way, altering an ARIA attribute on an element through JavaScript would work perfectly well, and the current value is obtainable through element.getAttribute("aria-role") or similar.
  4. I understand that ARIA is semantic and therefore belongs more directly in the HTML than mere presentation does. However, distinct advantages to moving ARIA information out into a separate document do exist:
    1. It allows me to “ARIAify” an entire website very easily, much as having CSS in a separate stylesheet allows me to change the design of a site very easily. At the moment, to “ARIAify” a website I have to edit every single page in great detail. If a site is already properly marked up and relatively consistent in the way it uses that markup, adding ARIA roles and attributes could be done relatively easily by adding one file, the ARIA stylesheet, and a <link rel="aria" href="..."> element to the head of each page.
    2. It avoids the validation problem, that ARIA attributes will currently cause a document to fail validation
    3. It reduces bandwidth required to serve a site, meaning that sites load faster and servers work faster and cheaper, in two ways:
      1. The “ARIA stylesheet” can be cached by browsers, meaning that it needs only be served once per site; embedding attributes in the markup means that every page gets larger and the attributes are not cached
      2. User agents that are not tied into native accessiblity APIs (for example, users who do not have the accessibility APIs switched on because they don’t need them) do not need to fetch the ARIA stylesheet at all, saving even more bandwidth

Hope this helps clarify my thinking.

Comments are welcomed.

Jif Lemon Day

Don’t forget the pancakes on Jif Lemon Day, they say.

No Pancakes For You

Some days I really miss Sam.

A WAI-ARIA “stylesheet”

Yesterday at the Multipack Presents event, Matt Machell spoke about WAI-ARIA, which is a way of marking up HTML with accessibility hints. (Think of it as an accessibility microformat, pretty much.) Anyway, the way it works is by adding loads of new attributes to HTML: to say “this div is actually being used as a slider”, you say <div id="myslider" aria-role="slider">. There are lots of similar new aria-* attributes: aria-describedby, aria-minvalue, and so on.

Anyway, I asked: why did loads of new attributes get invented? Why not have an “aria stylesheet”, where instead of <div id="myslider" aria-role="slider">, you put #myslider { role: slider } in a separate ARIA “stylesheet” file? And Matt said, hm, dunno, why don’t you write something to do that?

So here it is. This is in no way complete. Requires jQuery, too. What you do is add

<link rel="aria" href="first.aria">

to the head of the page, then include jQuery:

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.1/jquery.min.js"></script>

and then finally have this snippet of code:

<script>
$(document).ready(function(){
  $("link[rel=aria]").each(function(){
    $.get(this.getAttribute("href"), function(data) {
      $.each(data.split("}"),function(idx, stanza){
        var parts = stanza.split("{");
        if (parts.length != 2) return;
        var sel = parts[0];
        $.each(parts[1].split(";"), function(idx, directive) {
          var bits = directive.split(":");
          if (bits.length != 2) return;
          $(sel).attr("aria-"+bits[0].replace(/^\s+|\s+$/g,''),
          bits[1].replace(/^\s+|\s+$/g,''));
        });
      });
    });
  });
});
</script>

which takes an “ARIA stylesheet” which looks like

#first {
  role: slider;
  described-by: #second;
  value-min: 10;
  value-max: 30;
}
p + p {
  role: main;
}

and applies the specified ARIA attributes to the specified elements, by CSS selector.

This is rambunctiously untested, and the parser for the “stylesheet” is pretty noddy and not at all error-tolerant. If people find this useful as a concept then I’ll try and trick it up into something a bit better.

Whizzy JavaScript stuff

Yesterday I did a talk at the inaugural Multipack Presents event in Birmingham, about some whizzy JavaScript stuff that people might not know about. It covered things that are nearly available for use everywhere (getElementsByClassName, Array.forEach) right up to things that only have an implementation at the moment in one browser (server-sent events (Opera), local SQL database storage (Webkit)). The idea was to say firstly “look at all this cool stuff that’s coming up” but more importantly to say “look at all this cool stuff you can use right now if you want to!”

Talk available for browsing and downloading over at the Whizzy JavaScript Stuff talk page, anyway.

Thanks to the Multipack for having me; I hope there are many more of these events! There are event photos on Flickr, and I’m told there may be (incomplete) video of my talk available at some point (when there is I’ll link to it).

YUI3 and Launchpad

For the last week I’ve been in Berlin with the Launchpad JavaScript team building a set of cool widgets using YUI3 that will gradually start to appear in Launchpad and make its UI nicer. The LP guys have started to write up the things that they’re doing over on the Launchpad blog. I’ve learned quite a lot about YUI3 in this week; I need to do a writeup (or more probably a set of individual writeups and tips about stuff I’ve learned).

Now is not the best time, though, since YUI is being incredibly frustrating with its widgets; they don’t clean up after themselves, so if your widget creates HTML then it’s your responsibility to remove that HTML from the document later. And my widget seems to be creating its HTML twice, which is less than excellent. Frustration abounds.

That aside, though, this has been a good week; got a lot done, and I want to see Canonical be part of the web community like we’re already part of the Gnome/Linux community. Building cool stuff and talking about it and releasing it is going to help, there.

Cutting off your nose

“Doctor, Doctor, my toe hurts.”
(Doctor amputates patient’s leg, and his right hand and his nose into the bargain.)

The solution to “my audio isn’t working right” is not “uninstall PulseAudio”. Nor is it to complain that your distro didn’t give you an “uninstall PulseAudio” button. Stop suggesting it. I ran into one small audio problem and half the responses to other people mentioning it were “you need to completely remove PulseAudio”. Stop recommending that to people.

This has been a party political broadcast on behalf of the “there’s a time in the evolution of everything that works when it didn’t work” party.

IE6’s backlash

Lots of conversation about IE6 holding everything back (Christian, Robert, et al), which is something that people have been talking about for ages (me last year, me in 2005, Zeldman in 2001 in a more general sense). A point to remember here: no-one (well, no-one serious) is suggesting that IE6 users get a site which says “you are using IE6: bugger off.” Instead, the suggestion really is that IE6 get the same treatment as Netscape 4: it gets the unenhanced version of your sites. You’re already building sites that work in every browser (if you’re not, go away and start doing that), and you’re already building sites that give Netscape 4 the version without many enhancements. Why not move IE6 into that category?

If your argument is that IE6 people will not like your site without enhancements because it doesn’t do as much or doesn’t work as well then…you’re not building sites properly. Stop doing that.

More thoughts on Linglish

I still don’t have a decent name for “Linglish”, the toy scripting language for the Linux desktop that I was playing around with a couple of days ago. I’ve added a couple more features to satisfy my curiosity about how hard it would be to do, and I’ve read the comments on the previous post with a great deal of interest. Thanks to everyone who chimed in with thoughts.

First, what Linglish can now do:

tell screensaver to lock

A simple command: just tell one application to do one thing.

ask banshee’s engine for uri

Request the value of something from an application. If you do this from the command-line, the value is printed out:

$ python linglish/runner.py -c "ask banshee's engine for uri"
file:///home/aquarius/Music/New%20Order%20-%20World%20in%20Motion).MP3

tell banshee’s engine to pause
tell screensaver to lock

Run more than one command in a script

tell tomboy to FindStartHereNote
tell tomboy to displaynote with the result

Call a command which returns something and then do something based on that: Tomboy has no “show the Start Here note” function, but this does it fine by getting a reference to the Start Here note and then displaying it. The latter command could also have been written as tell tomboy to displaynote it or tell tomboy to displaynote FindStartHereNote

wait for banshee’s eventchanged
ask banshee for currenturi
tell tomboy to createnote with it

Wait for an application (Banshee) to send a signal (a song has stopped playing or started), then when it happens ask for the value of a property (the path to the currently-playing song), and finally call a different app (Tomboy) to create a note with that path as its name. This example will then exit: if you want to create a new note every time the song changes, then wait repeatedly for the signal rather than just waiting for it.

Next, some musings:

One thing that this has revealed to me is that there are quite a few apps which I’d like to interact over D-Bus with which don’t provide an API to do so. The glaringly obvious example here is Nautilus (and indeed there is a bug requesting a D-Bus API), and a part (a small part) of why I’ve built this is that if there’s an easy way to encourage people to write little programs controlling their desktop then that will encourage application developers to build APIs to their apps. Zenity doesn’t have one either, which makes interaction from these little Linglish scripts a bit difficult; I suppose I could build “display dialog” commands into the language but that seems a bit off. On the other hand, one of the advantages here is that there’s nothing stopping someone building a thing which is just a D-Bus API and which then calls out to Zenity to do the work.

A second is that our D-Bus APIs are not necessarily brilliant. Picking a silly example, if you want to find Tomboy’s version using Linglish you have to tell tomboy to version, which sounds rather stupid; it should be “ask tomboy for version”, but Version() is a method rather than a property in Tomboy’s D-Bus API. (I’m not picking on Tomboy here; they have a pretty comprehensive API, and I’ve been testing and developing Linglish using primarily Tomboy and Banshee.) Linglish is sort of designed with the conceit that methods are verbs, hence the “tell someapp to dosomething” syntax, which sounds deeply weird if your methods are not actually a verb.

It’s also jolly hard to work out what D-Bus APIs are actually available. Well, that’s not true: if you’re me, or a hacker like me, then you can use J5’s fantastic D-Feet D-Bus browser. I think this problem is best solved with tools used to create the language rather than the language itself, although there’s more on this in the future-development section below.

There were plenty of comments on the last post saying that this was a stupid idea and that it made much more sense to have a syntax like screensaver/lock or screensaver.lock() rather than tell screensaver to lock. I, personally, do not agree with that. I’m not necessarily suggesting that I’m right and they’re wrong, or that neophytes will indeed find my way easier: just that this is an alternative way. If you think that Python or Smalltalk or any one of a dozen others are a better approach, go for it: I’m certainly not stopping you.

Thirdly, questions about what it might do in the future and whether those things are a good idea:

The original conception I had for this in my head is now basically done. You can send commands to programs, you can tie programs together, you can get info out of a program and print it out. It would be able to do half the little scripty tasks I want to do on my desktop (assuming that the APIs existed to do them, which they mostly do not). Here are future things it could do, in rough order from small to big:

  1. Be cleverer about calling methods on applications with more than one object. At the moment you have to tell banshee's engine to pause, because Banshee exports more than one object. Since only one of those objects actually has a Pause() method, tell banshee to pause makes more sense.
  2. Have Linglish be able to document an application. ask linglish about tomboy which then prints out Tomboy commands you could use by introspecting Tomboy’s D-Bus API would be pretty nice. One big problem with this is that for most apps they need to be running to find out what API they offer, so ask linglish about banshee would start it up.
  3. There are currently no control statements. This is a problem if you want to do anything even semi-complicated in a script, especially since the common approach to D-Bus signals in Linux apps seems to be to generate a SomethingHasChanged and then pass a whatchanged parameter; Banshee fires StateChanged('paused') and StateChanged('playing') rather than Playing and Paused signals. NetworkManager has something similar. It’s understandable why: you get one signal in a few different flavours rather than a multitude of signals. Inconvenient for this, though, because to vary what the script does based on a parameter you have to have an if statement (or something similar). I’ve been thinking about this: I do not want to build a proper language. If you want that, learn Python. But…maybe it needs control statements. I don’t know. I’m against it, but if this is useless without them then that’s a strong argument that the effort is not worth it.
  4. A script editor. This would allow people to write scripts without having to know the names of any of the functions you need to call — popup completions and the like. This is even more problematic than ask linglish about whatever, since there’s no way of saying “which apps in the world offer a D-Bus API?” — most apps do not install an activation file, which means they must be running for any script editor to even know they exist. It’s also a lot of work, although most of the heavy lifting is done by GtkSourceView.
  5. Packaging and stuff. If this is likely to be useful I should make .debs of it and so on and make it easy for people to install and everything.

And finally…

The overarching question: is doing more of this a good idea and worth the effort? Your comments gratefully accepted.

Linglish, or, some thoughts on a scripting language for the Linux desktop

After a few hours of fiddling around, I’ve come up with a thing I’m calling “Linglish”: it’s a very simple scripting language for the Linux desktop. It looks a lot like AppleScript, and it’s nowhere near finished. It basically allows you to write in a sort of bastardised English which then calls D-Bus functions, so you can say things like:

  • tell screensaver to lock
  • tell banshee’s window to present
  • tell banshee’s playerengine to pause
  • tell tomboy to createnamednote withMy Named Note
  • tell guake to add_tab
  • wait for tomboy’s noteadded then tell banshee’s playerengine to toggleplaying
  • wait repeatedly for tomboy’s noteadded then tell banshee’s playerengine to toggleplaying
  • wait 6 times for tomboy’s noteadded then tell banshee’s playerengine to toggleplaying

Like I say, it isn’t finished yet (the above all works, but there’s lots more that needs to happen). At the moment, for example, there’s no way to run more than one command, or to get a return value from any function and react on it. The question is, is this a good idea that’s worth pursuing? This will never be (and is obviously never intended to be) a replacement for a proper language; if you want to do something semi-complicated, drop into Python or JavaScript or Vala or C and make the D-Bus calls yourself. However, I can see it being useful to help people who don’t want to get to grips with proper programming but still want to control their applications.

If you think it’s a bad idea, please let me know why and what you think should happen instead. If you think it’s a good idea, then here are a couple of other thoughts that I’ve had on how it might evolve:

  • A script editor program would be nice, which could dynamically inspect D-Bus to help you write scripts. It could compile a script to an executable that wouldn’t need the script runtime either without too much difficulty (one big Python script, perhaps, or using glick to make an actual executable).
  • Obviously it needs to be able to run multiple commands, and have later ones react to what happened in earlier ones. I’m imagining an ask banshee's engine for position sort of sentence, which would get the Position property and then stash it in an invisible result variable, meaning that the next command could be tell banshee's playerengine to seek to the result + 20 or something similar.

Key question is: is this worth pursuing? Or is it reasonable to demand that people who want to script our desktop should learn a more real programming language?

Code (written in Python) in svn at http://svn.kryogenix.org/svn/linglish/; it’s only half a dozen files. If you want to fiddle with the grammar to add new ways of parsing commands you’ll need yapps2 (in Ubuntu as yapps2), and you’ll need the yapps2 runtime to actually run any commands (in Ubuntu as yapps2-runtime).

Syntax: python linglish/runner.py -c "tell tomboy to createnamednote with 'named note'"

LugRadio Live UK 2008 videos coming online

Just a quick note to say that the LugRadio Community Hero and general video god, Tony Whitmore, is doing a great job of getting videos of talks from LugRadio Live UK 2008 available online for people to watch. They’re not all there yet, and more will be showing up over the next short while, but there’s already a really good proportion (including the LugRadio live show). Go grab them:

LugRadio Live UK 2008 talk videos

Opera Web Standards Curriculum: the JavaScript version

The Opera guys have been putting together a Web Standards Curriculum — a sort of school textbook of modern web development. Anyway, after a certain amount of cajoling from Chris “Dark Sanatic” Mills I came through on my promise to actually write some articles for it. They’ve now been published in the JavaScript section, if you like that sort of thing: one on modifying the HTML DOM tree and one on simple animation. Enjoy.

(I am proud I was not as whiny as Nyman — if you saw excerpts of my emails to Mills & co they’d all say “oh, piss, yes, I did say I’d do that, didn’t I? I’ll get it done this week, promise.” Who’d be an editor, eh?)

Mini hippo returns

I once saw a birthday card with a picture of a small hippopotamus on it executing a 180° rotation, and underneath it said: mini hippo returns. Made me laugh.

Mini Hippo returns

Mini Hippo returns

Anyway, it’s time for the annual it’s-my-birthday post (now in its seventh great year!), given that I am now as old as Christ. Well, I am according to the book Hannibal, anyway; the age of Jesus is somewhat murky and disputed, and clearly he didn’t exist anyway which makes speculation somewhat pointless. I am now one third of the way to my telegram from the Queen (which I am gratified to discover still happens when you hit one century of age), and according to the Death Clock I’m more than halfway to being dead (which rather puts the kibosh on the whole telegram thing).

In the last year:

  • I’ve left a job in a law firm and started a job in a radio company
  • I’ve split up from my wife (although we remain good friends; am going drinking with her this evening, in fact)
  • I’ve been to America (twice) and Ireland and Holland
  • I’ve lived in Jono’s spare room and then come back to my house (which I still can’t sell)

In the last month:

  • I’ve left the job at the radio company and started a job at Canonical
  • I’ve eaten caviar for the first time
  • I’ve rekindled friendship with someone I haven’t seen for years
  • I’ve booked tickets to go to Hacking At Random in August

In the last day:

  • I’ve eaten way too much bangers and mash
  • I’ve started thinking about server-side JavaScript web frameworks in a decent way
  • I’ve looked at CouchDB and thought about how to use it
  • I’ve written to my MEP

In the last hour:

  • I’ve smoked five cigarettes
  • I’ve become 33 years old

Here’s to another twelve months. Cheers.

The European Parliament and the Term Extension Directive

Those of you who are involved with digital rights campaigning and live in Europe may be aware that the European Parliament are currently mulling over extending the pan-European term of copyright from 50 to 95 years. The US recently increased their term of copyright (at least partially to “bring them in line” with Europe), and now Europe are being asked to increase theirs (at least partially to “bring them in line” with the USA). Copyright extension keeps music and composition and created works away from the public: I won’t rehash the arguments in favour of the public domain and against an ever-increasing term of copyright; most people reading this are likely to have heard them before, and if you have not then I strongly recommend Lawrence Lessig’s Free Culture, a book (and free-to-download e-book) which treats the subject in exhaustive detail. Suffice to say that I’m convinced by these arguments.

Anyway, if you’re in Europe and you agree with me on this rather than the music industry, you can write to your MEP. (In the UK, you can do this through WriteToThem.) My letter is below; it takes various ideas from Open Rights Group writings and Gary Fleming’s similar letter.

Note: don’t just copy mine (or anyone else’s). Your MEPs need to hear from you, their constituent, in your own words.


Dear [my MEPs],

I am writing to you all today because you represent me in the European Parliament. As such, I would like to bring to your attention my concern (a concern shared by many others) over the proposed extensions to European Copyright law (the Term Extension Directive).

You and your fellow MEPs are being asked to nearly double the term of copyright afforded to sound recordings. Industry lobbyists suggest that extending copyright term will help increase the welfare of performers and session musicians. But the Term Extension Directive, which will be voted on by the Legal Affairs Committee in a few weeks’ time, will do no such thing. Instead it will hand millions of euros over to the world’s four major record labels, money that will come direct from the pockets of European consumers. The Commission’s own Impact Statement states that increased sales revenues from the extension of copyright terms will be divided approximately 90% to the record labels and 9% to the top fifth of performers, leaving only one-onehundredth of these financial benefits to go to the remaining 80% of musicians. This one-onehundredth actually means that the projected gains for the vast majority of performers are meagre: the highest-earning of these performers can expect to receive 27 euros a year. Twenty-six euros is not likely to significantly benefit the welfare of a performer or session musician!

The UK has shown itself to be a leader in intellectual property policy; the Gowers Review of Intellectual Property, conducted at the request of the UK government, specifically recommended against increasing the term of copyright. It may amuse you to note that the USA extended their length of copyright terms “to bring them in line with Europe”; you and your MEP colleagues are now being asked to extend European copyright, in part to “bring us in line” with the USA! Professor Bernt Hugenholtz, who advises the European Commission on intellectual property issues, wrote an open letter in which he called the proposed extension “a deliberate attempt on behalf of the Commission to mislead Europe’s Parliament”. Andrew Gowers himself has spoken out in an article in the Financial Times in December against this “out of tune” extension.

If you honestly believe that almost doubling the term of copyright in the EU and ensuring that the majority of the money thus gained goes to record labels is a good thing, then I can respect your views. However, if you think that you’re being asked to exercise your power as our elected representatives when you may not have been given the most germane facts to the case at hand, then I’ll suggest here some further resources you may find useful.

Consumer advocates have produced a video, “How copyright term extension in Sound Recordings actually works”, which is available at http://www.youtube.com/watch?v=kijON_XODUk for you to watch, and I’d urge you to so watch it.
A joint statement, signed by the European Bureau of Library, Information and Documentation Associations (EBLIDA), 42 consumer rights organisations across Europe, and and IFLA, the umbrella organisation representing over 650,000 library and information professionals worldwide, was sent to MEPs who sit on the committees that will decide the flawed Term Extension Directive’s future; you can read the statement at http://www.openrightsgroup.org/2009/01/21/consumers-citizens-and-information-professionals-around-the-world-unite-to-condemn-copyright-extension/ and see more detail.

I would urge you to vote to reject the Term Extension Directive, as per Amendment 15 of the ITRE opinion (David Hammerstein).

I’m happy to discuss this further if you would like to.

Best regards,

Stuart Langridge

Working with Internet Explorer

Building HTA desktop apps with Internet Explorer is a real treat for a web developer. You get to work with desktop features such as native drag and drop, system icons, reading and writing files, encrypted SQL server embedded databases, and chrome-less, non-rectangular windows (even with HTML!). You also have access to all of the features of Windows, the most popular operating system in the world, like audio and video, sound transforms, uploads and downloads, byte arrays, cryptography, and loads more. Best of all, you get to have a single target environment, in Internet Explorer — JavaScript expressions in CSS, VML and HTML+TIME, and no compatibility issues with other browsers. It’ll also work out of the box on nearly 90% of the computers in the world without installing anything else — no “runtimes”, no “installers”, no extra code required. Just do it.

Does this sound like a stupid thing to say?

Then it sounds just as stupid when people say it about Adobe AIR.

Of course it’s easier to develop HTML apps when you have only one target environment. The problem is that that environment is still controlled by one company.

Those of you about to say “but, but, but, AIR is cross-platform! fight the evil that is Windows!”, feel free to replace “Internet Explorer” and “HTA” above with “Firefox” and “xulrunner” or “Prism”.

Update: it has been correctly pointed out to me that this post was a bit harsh. I had a headache and was up early, is my excuse. While I absolutely stand by the points made here (AIR is no more the Open Web than Internet Explorer HTAs are; why do people who hate HTAs love AIR?), I should have been more gentlemanly about the point. Throwing bricks helps no-one. My apologies, Mike.

7 Things You May (Or May Not) Know About Me

I’ve been tagged by Pat with another one of these meme things. Now, I did this about a year ago and I don’t know whether this is the same meme coming back around (in which case it’s mutated from 5 things to 7) or just someone else making up an unoriginal concept.

Someone should write a thing which traces these memes back to their source and then blows up the source’s computer.

Anyway, I’m not sure there are seven things, especially when you consider I’ve already provided five, but here goes.

  • I’m trying to sell my house and move to London. Anyone who’s thinking of moving to the West Midlands, buy it, you know you want to.
  • Despite being a prescriptive grammar lunatic, I still get confused by the difference between “who’s” and “whose”. I have to manually think “who’s is short for ‘who is’”, and phrases like “Barack, whose inauguration was yesterday” still don’t look right. Grammar blind spot.
  • I tried out one of these computer dating sites. It was less than successful.
  • I “managed” a “band” (both of these terms are somewhat loosely applied) when we were at university. Of course, “manager” also meant putting all the instruments (a drum kit, a Hammond organ (!), guitars, etc) into the back of my Fiesta, but I did at least sort out a couple of gigs. Simon Cowell eat your heart out.
  • I use Flash and Skype and Opera. So much for my open-source zealotry.
  • I got arrested in Texas once and spent the night in the police station. It’s all sorted out, now, though, so I’m allowed to go back.
  • I work for Canonical now. (Probably people know this, but I keep getting “wow, hadn’t heard that!” responses, so maybe the word hasn’t got out.)

Apparently I’m now supposed to tag seven more people, who then tag seven more, and yea even unto the fiftieth generation like necrotising fasciitis. So:

  1. Bruce Lawson, because he’s likely to come up with seven comedy things
  2. mrben, because he tagged me last time with this horrible circulating disclosure meme
  3. Andy, because ’twill be interesting
  4. Tom, one of whose secrets will be “I still haven’t got my damned Christmas presents from Stuart” — one of mine ought to be guilt or something. I’ll be around soon, promise.
  5. Stuart Colville, because he’s not busy enough at the moment :-)
  6. Kevin Smith (no, not the director), because he never writes anything these days
  7. Josh Blount, so I can learn some useful blackmail facts about someone on my team!

Go to it.

A nice remote for my TV

My television is run by the MythTV PVR software, which I use for watching films and recording TV and playing music and the like. Now, Myth is sort of organised around having a horrible massive remote control with a million buttons on it, which I can’t stand. I want something nice and simple (Apple Remote sort of thing), but I wanted it to not use infrared (because IR is a pain in the arse, and you have to be pointing it at the TV, and apparently there are different sorts of IR which are incompatible (you can’t buy an Apple Remote and point it at any IR receiver you like and have it work, much to my disgust)).

TomTom make a Bluetooth remote control for their high-end satnav units. (It’s available at Amazon for thirty quid, which is a bit steep; I think I paid a bit less for it.) Anyway, owing to the wonders of Bluetooth and the Linux Bluez software all working nicely, just pairing with the remote means that it works like a keyboard and everything’s perfect.

If you see any guides out there on the web telling you to use “hidd” on the command line to set this sort of thing up, they are wrong and out of date. Use the Bluetooth icon on your Gnome panel to pair with the remote, and then use Preferences to connect to it. That’s all.

blurry

annoying tease

How my desktop looks

This is more for my benefit than anyone else’s.

So, it’s now early 2009, and after a bout of tweaking how my desktop looks, I’m pretty happy with it.

My Ubuntu desktop, January 2009

That’s the DarkRoom Gtk theme and my own Prelude-dark Metacity theme (a darkened brown version of the Prelude Metacity theme that Thomas Thurman made for me), with the gorgeous Smokikon icon set, all application, desktop, and document fonts set to Salem 8 point (from the ttf-arabeyes package), with subpixel smoothing turned on, and my simple-but-I-like-it inspired-by-the-Mac-bootsplash desktop background*.

So now when I buy a new laptop (it’s gonna be the Dell M1330 with Ubuntu on it unless anyone comes up with a reason why not before the end of the month), I’ll know how to make it look like this.

The length of the taskbar

Alberto Ruiz talks about the taskbar in Gnome wasting a lot of space, and how launchers, applets and notifications could all be merged (in a post which sounds rather like a pitch for OS X’s Dock, or at least a pitch for awn, which is rather like it).

I personally turned off my taskbar (and the whole bottom panel) ages ago, because I want more screen room. Instead, I added a Window Selector to the top panel, on the far right-hand-side. To switch between apps by name, therefore, I just throw the mouse up and right into the corner and click, and then choose an app from the menu I then get. I really haven’t noticed the lack of the taskbar at all.

Gnome panel window selector

(To be honest, I don’t even do that most of the time; I alt-tab between apps. To be truly honest, now what I do is throw my mouse at the bottom left corner which does Compiz’s scale plugin (the OS X Exposê thing), but not everyone’s running Compiz.)

(An extra note here: OS X has a nice trick where you can click on the window list you get from holding down alt-tab. Can we do that?)

I’m not sure about merging launchers and notification icons, though. There’s stuff that I want a notification icon for (XChat-Gnome, the new mail notifier, Pidgin) that I don’t need a permanently-visible launcher for because I hardly ever start them up (once at the beginning of a session, or not at all because they start themselves).

My window theme

Thomas Thurman, champion that he is, took my request for a theme for Metacity that clones the XFCE Prelude theme and went ahead and did it. What a hero.

Anyway, I’ve tweaked his work a little to make it closer to the XFCE theme (primarily making the border thinner and nudging some of the colours, and hiding the buttons on inactive windows) and you can grab the theme file. Save it as $HOME/.themes/Prelude/metacity-1/metacity-theme-1.xml, then say System > Preferences > Appearance > Customise > Window Border and choose Prelude.

Some questions that might spring to mind:

How do you move windows around when there’s no title bar?
Hold down Alt and drag them
How do you know the title of a window when there’s no title bar?
It turns out I very rarely actually need that. If I really desperately need it then I just throw the mouse at the bottom-left corner which shows me all the windows (it’s a clone of Exposê on the Mac) and that shows the titles of every window.
How do you close a window when the close button is so small? Don’t you know anything about Fitts’ law?
Alt+F4 or Ctrl-Q, normally.
Isn’t having to use keyboard shortcuts annoying and slow and wrong and bad and anti-Tognazzini’s advice?
Yep. I wouldn’t give Prelude to a new user, absolutely not. I’m not a typical user.
Why do this at all?
Because I think it looks pretty. If you don’t then don’t use it.

Giving searchhi a bit of a makeover

A user of one of the scripts I wrote a while back, searchhi, dropped me a mail to say: it would be handy if I could take some action if no hits are found. After a bit of probing, it turned out that they were using it for an in-page search — what searchhi actually does is look at the referrer to see if you came here from a Google/Yahoo search and highlight the stuff you searched for — so you could fill in a search form and then search the words in the page and highlight them. I’m at a bit of a loss as to how the built-in browser search (which is Ctrl-F for everyone, I think, although Macs might be different, and I use / on Firefox) doesn’t satisfy this need, but needs must and all that. Hacking both of those things in (have a <form class="searchhi"> in the page and its first textbox will automatically be used as the search entry) was relatively quick.

The nice thing about this is that I took the opportunity to tidy the script up a bit; it was written some time ago, and created its functions in the global namespace, was careless about var, that sort of thing. I’m now a bit happier with it — it passes JSLint for a start, modulo that I disagree with Douglas about single-line if — by which I mean that I don’t cringe when I look at it.

(I haven’t documented the changes on the searchhi page itself, because the in-page search stuff is obviously JavaScript-dependent and that’s not how you should do it, so I don’t want to encourage people to use it.)

Back from UDS

Last week I was at the Ubuntu Developer Summit, the six-monthly big meetup for Canonical employees and the Ubuntu community to get together and work out what’s in the next version of Ubuntu Linux and how to do it. It was fascinating meeting everyone and seeing it all up close. Lots of stuff went on: I got interviewed by the Ubuntu UK guys for their podcast; I caught up with a few people I hadn’t seen for a while and lots of people I’d never met face-to-face before; I threw together a quick “lifestream” bit of JavaScript which would track a tag across various sites and it ended up on Launchpad (so if you want a trivial way to display a lifestream for a conference, grab the script and make it better); I asked everyone I could think of whether I should insist on buying a laptop with Ubuntu on it and which one I should get; we went to the Computer History Museum and indulged in the geek oneupmanship game of saying “owned one of those, owned one of those, wanted one of those” (apparently the PlayStation 1 is now Computer History); and I drank a fair amount of beer. Was a good week.

I was there because I was paid to be so by Canonical. I start work for them at the beginning of January. While there I met the people who will be my team when I start, and saw some of what they’re working on, and I’m really rather excited. I’m going to be part of Online Services. Can’t wait to get going on it. I get to make the desktop I use be better.

Sending posts from Twitter to Identi.ca part 2

A while back I wrote a reflector which sent posts from Twitter to Identi.ca if you want to post to both. However, that required running your own code, which is hardly in the spirit of Web 2.0 and cloud computing and all that. So, now, here’s how to send your posts from Twitter to Identi.ca without running any software yourself.

  1. Sign into Twitterfeed with your OpenID (Ubuntu users, if you don’t have an OpenID you can use your Launchpad ID: https://launchpad.net/~fred-bloggs )
  2. Say “Create new Twitter feed”
  3. Change it to be a laconi.ca feed
  4. Set the feed URL to be http://pipes.yahoo.com/pipes/pipe.run?_id=WvUZFt_G3RG6Veiqbbsjiw&_render=rss&twitteruser=YOUR_TWITTER_USERNAME
  5. …and you are done

The pipes.yahoo.com stuff is there because if you just use twitterfeed to send your Twitter user RSS feed direct to identi.ca then all your posts have “sil: ” at the beginning (or whatever your username is). The Yahoo pipe strips that off.

If you want to post to Identi.ca and have your posts show up on Twitter* then Identi.ca does it for you; just set it up in the Settings section of Identi.ca.

Helvetireader in Mozilla Prism

Jon Hicks has just released Helvetireader, a lovely minimalist theme for Google Reader. He’s implemented it as a GreaseMonkey script which pulls in the CSS file direct from helvetireader.com, which is a cool touch. He also notes that “the Helvetireader user script is ideal for using with Fluid.app to create a standalone application”. It is, of course, also ideal for using with Mozilla Prism for those of us not on a Mac (or those on a Mac who prefer Prism to Fluid). Grab helvetireader.webapp for all the well-styled-Google-Reader-in-its-own-window you’ll ever need.

(Those of you of a technical bent: all I did was add a webapp.css saying @import url(http://www.helvetireader.com/css/helvetireader.css); to greader.webapp, so you could do that yourself and add any extra customisation you want to that file.)

14 minutes 12 seconds of fame to go

Me on Top Gear

What I’ve got open

Rather a lot, I find myself having to save a file somewhere temporary like my desktop just in order that I can immediately upload it to some website, or attach it to an email, or something similar. It’s irritating. I have to explicitly save it; I have to think up a name for it; then I have to switch to my mail client or my web browser and browse back to the file I’ve just saved and choose it by name to upload/attach it; then I have to browse to it again in the file manager and delete it. Now, there’s lots of talk about draggable icons for files and so forth, so I can just drag the save icon out of, say, the Gimp directly into the browser. The ROX apps do this; Risc OS did it too. That’s a nice long-term goal, but it requires touching every app in the universe, and it’s hard.

I had a thought about a workaround. It’d be quite cool to have a folder called “Open Documents” which, when opened, showed an icon for each document available in each application. Then, when you pick a “file” from this “folder”, it tells the relevant application “save it as some random temporary name” and then attaches/uploads some random temporary name. So you don’t ever have to manually do the save/delete thing.

I only really strictly need this for the Gimp, to be honest; I don’t upload textual files, I cut-and-paste them. So, a rather crufty approach:

  1. Download gimpdbusapi.py and put it in $HOME/.gimp-2.6/plug-ins/ and mark it executable. It’s a Gimp extension which makes two functions available over D-Bus: image_list and save_as. (This could be the starter for making all Gimp functions available over D-Bus, with a __getattr__ hook, the gimp.pdb object, and a bit of introspection.)
  2. Download gimpfs.py, a Fuse filesystem in Python, which talks to the Gimp extension via D-Bus to get the list of currently open images in the Gimp (even if they haven’t been saved).
  3. Create an empty folder ($HOME/Open?) and python gimpfs.py $HOME/Open to mount the view of Gimp open documents on that folder.

There might be better ways to do this, with gvfs and so on, and it would be way better if it didn’t have to use tempfiles, and so forth, but this is a proof of concept. What would need to happen to have all Gnome apps’ currently open documents automatically appear in a folder ready for choosing?

behave!

After watching @darrenf (a) tell an awful lot of people to behave on Twitter and (b) have to manually type it in every time, thus providing wear and tear on his hands which mean that he can’t fix bugs instead of me, I present: behave.user.js, a Greasemonkey script to tell people to behave on Twitter. Just hover over a name and click the ! to tell that person to behave. Winner.

Pause torrents while I’m using the computer

I use the Transmission BitTorrent client, and it’s pretty cool. However, it’s irritating when it eats my bandwidth while I’m trying to do stuff. So, one obvious hack would be to disable it when the screensaver is off (i.e., I’m using the computer) and enable it only when the screensaver is on (i.e., I’m in bed). Fortunately, Transmission has an API (which you have to enable by turning on the web interface in Preferences) and you can watch the Gnome screensaver for changes. So, a quick Python script later, and throw that Python script and Transmission itself into your session Startup Programs to make them run whenever you log in, and Bob’s your uncle. the script:

#!/usr/bin/env python
import dbus, urllib
from dbus.mainloop.glib import DBusGMainLoop

START_TORRENTS = "http://localhost:9091/transmission/rpc?method=torrent-start"
STOP_TORRENTS = "http://localhost:9091/transmission/rpc?method=torrent-stop"

DBusGMainLoop(set_as_default=True)
sess=dbus.SessionBus()
def sig(screensaverActive):
  if screensaverActive:
    data = urllib.urlopen(START_TORRENTS).read()
  else:
    data = urllib.urlopen(STOP_TORRENTS).read()

sess.add_signal_receiver(sig, 'ActiveChanged','org.gnome.ScreenSaver')
import gobject
loop = gobject.MainLoop()
loop.run()

Trying to understand YUI 3

I’ve been looking at YUI 3, because I ought to know about it and I currently don’t. I used YUI 2 for a few things and found myself perpetually frustrated with the documentation and the general feel of it, but I figured that maybe that was just me. (Disclosure: I’m a jQuery guy. Use it for everything. So I’m biased, right out of the gate.) Anyway, my frustration with the YUI documentation doesn’t seem to have been alleviated in version 3. This is a case study in how someone new to the YUI 3 library sees the documentation. (Well, it’s really a set of stream-of-consciousness rants, because that’s the best way I can think of getting my sense of confusion and discombobulation across.)

The underlying problem I always had with the YUI 2 documentation was that the examples show how to do one specific thing but don’t explain why to do it that specific way, and don’t seem very generalisable to do other similar things. So they’re hard to learn from. The reference manual, on the other hand, is useless. It gives you a textbox and says “Start typing to find a property/method/event/config”. If you already know what you’re looking for, if you know which function you want to use but can’t remember the order of the parameters that you need to pass to it, then that’s fine. It’s a dictionary. But you can’t learn a language from a dictionary, and you can’t learn the YUI from the reference manual. I hardly ever find myself thinking “I need to use the YUI.Get.script function but I can’t remember the name of the parameters”. Instead, I find myself thinking “I want to execute a JSON-P script; how do I do it?” Now, the jQuery documentation has a similar problem, to some extent, but critically it shows you all the functions in a list, so I can look through them and work out which is likely to be the one I want. The YUI does not. The jQuery docs also have inline executable examples with each function, so I can see working code and test it. The YUI reference manual does not.

But I shouldn’t start with the reference manual. The YUI docs specifically say to , so I did so.

The very first example is showing how to attach an event handler to a node. Fine as far as it goes (and I like the idea that you get passed a full-on event object to your function whether you’re in a browser that supports that or not), but…the code in the example just drifts in space. It’s not wrapped in an onDOMContentLoaded or anything. (I admit it’s the first example, which means you don’t want to load people down with infrastructure just so they can write a click function.) So, since there’s a working example in the page, I looked in the source myself, and we get

YUI({combine: true, timeout: 10000}).use("node",
function(Y) {
 ... code from the example...
});

Ah, OK, so that’s onDOMContentLoaded, is it? a new YUI function. I’m sure it’ll be explained later.

Moving on, the next example explains onAvailable, onContentReady, and event:ready — three different “is the thing ready for me to use” load events. (All of which make sense at different times, and are potentially useful.) That’s all good, but…the previous example, even after I’d looked in the code, didn’t use any of them! How did that work?

Ah, a feeling of doom creeps over me. More disclosure: I really, really don’t like the Yahoo practice of putting your JS inline at the bottom of the page. I think it means that my JS isn’t separated out into different files where it’s easy to edit, it makes refactoring the page hard because you have to care exactly where your script elements are and be careful if you move HTML elements around, and it’s a lot easier to teach people to make their JS unobtrusive if you can offer the rule “Put all your JavaScript in separate files and don’t have any anywhere in your HTML”. I know there are good reasons why Yahoo do it, and I accept those reasons. If I build a site which gets as many hits as they do then I’ll test both ways and the extra three milliseconds you get from having the JS in-page without DOMContentLoaded may make a big difference. For most of the stuff I write, though, I don’t like it and try to not use it. So, the first example was obviously reliant on that (because it’s not hooking any load event at all), but didn’t say so. Moving on, the next example I read, about nodes, does the same thing. As far as I can tell, nothing anywhere in these examples has said “make sure you put this example code after the things it’s referring to”. If you don’t do that (say, if you put it in the head because that’s where you’ve been taught that JavaScript should go) then it plain won’t work, and you won’t know why. (Maybe I missed the 72-point red writing which says this? I hope I did.)

Next example I read (event delegation, a thing I like very much): doesn’t show why the clicked items turn green (obviously CSS, and indeed it doesn’t take long to find the link in the source), but also…when I click on one of the items and it turns green, there’s a subtle animation effect to it, as if the green colour expands out from the centre of the item. It’s quite a nice effect. I can’t for the life of me find what’s doing it, though. (Doesn’t do it in Midori, a webkit browser, so maybe it’s Firefox?)

I spent ten minutes trying to work out why clicking on an item sets a class (”yui-pass”) on that item and then alters text in all non-yui-pass items, rather than just using e.target. Of course, the reason is that a second click on a different item should set that second item to green and not unset the first green item. Fine and dandy: a note about that in the example would have helped, though. Yes, the examples are there to demonstrate YUI, not to explain how to produce a specific effect, but…what people want is a specific effect. Explaining how it works would help with that. Explaining the YUI parts of an example but not putting them in the context of the rest of the code is like explaining how to build a house with a two-hour lecture on bricks without ever mentioning that you need mortar to stick them together. “The rest of the code” here is a couple of lines, but the example would make much more sense if it was all explained.

Once I’d got this far, I started thinking, hm, hasn’t changed, still the docs are written for someone who isn’t me and I don’t get them. So I started dotting around picking and choosing bits to look at rather than going through step-by-step. One of the features I like most about jQuery is that I can call a JSON-P script and still specify my callback function inline, rather than having to separate it out and give it a name and pass that name as callback=myCallback to the JSON-P script. (It gets given a name under-the-covers by jQuery, of course, so that the callback does have something to call, but I don’t have to think about it. I like inline functions.) It’s be useful to me if YUI 3 could do that, so I thought I’d have a look to see if it’s possible. I don’t think it is, but…I can’t tell. The docs don’t seem to mention the idea of loading scripts that call a callback function at all. Instead, I think you’re supposed to use YUI.Get.script and read the JSON out of the nodes array that you get passed. Perhaps. Here we come back to my problem with the YUI docs: I know what I want to do, but not how to do it, and there’s no way to answer my question. If there isn’t an example dealing with it, I am out of luck.

Someone tell me how I ought to be reading the documentation. Maybe I’m missing something. But it does rather feel to me like the docs are reference material: they’re there for people who already understand YUI. The examples are incomplete — focusing on just the part you’re trying to show is understandable, but if the example won’t work without the other parts then you have to show the other parts too! If your example only works if it’s wrapped with YUI().use("node"), function(Y) { ... }) then you have to show that. If it only works if it’s wrapped in DOMContentLoaded, or if it’s placed at the bottom of the page in a script element, then you have to say that. Yes, it’s a ballache to have to explain how events work and how loading works and not get to any real concrete examples until chapter 3 or 4 of your documentation. But people need to know that stuff or your examples will not work when someone uses them without knowing the context.

MythTV alarm clock

This morning my alarm clock didn’t go off, and I didn’t make it to work. That’s gotta be fixed. Since this weekend I got a whizzy new MythTV setup around my house, that seems like the ideal thing to wake me up.

However, MythTV plugins are written in C++, and I don’t do C++ because I’m a Python guy.

So, something of a hack. It is possible to add a menu item to MythTV which runs an external program. So, thought I, that’d be one way to do it, and indeed it works. You create a new “menu theme” which launches an external program by name. The Myth menu theme development guide explains how. Then, write a small program to accept user input to set an alarm (I used pygame, which seems more in keeping with the MythTV approach than Gtk), and pow, Bob’s your uncle.

Actually, I used pygame primarily because I needed the MythTV keys to navigate around the little alarm-setting program. I’ve got some weird keys bound to do navigation in MythTV (2, 4, 6, 8 for up, left, right, down) and I’ve got no idea how you can make the 6 key mean “go to the next field” like Tab does in a Gtk application. In pygame that’s easy, so I did it that way; at some point in the future it should also allow me to theme the app so it looks like your MythTV theme, but I didn’t get around to that.

The way it actually creates alarms is by putting them in your crontab, which is easy and satisfying and what cron is for.

Anyway, code in Subversion at http://svn.kryogenix.org/svn/mythtv-alarm-clock/ if you want to have a play.

I suspect the MythTV people would be horrified by this approach. A few of them tried to convince me that I should learn C++ because it’s not that hard…

When the meme comes around

blah blah blah meme blah blah blah fifth sentence on page 56 of nearest book blah blah blah.

“Thorn, that’s beautiful!”

Not much of a sentence. On the other hand, the book is The Complete One-Volume Edition of Bone, the graphic novel.

Memo to self: do not search the internet for “bone” again in a hurry.

Page 56 is about as far as I’ve got with the book so far. It’s pretty heavy going, what with it being 1400 pages and all. I was lent it by Tim when I issued a cry for help for not having books. (All my books got packed up when I assumed I’d be moving house in short order…and then the economy swirled down the toilet and no-one’s buying houses. So I have a big house that I rattle around in on my own, and no books. Tim delivered me a box full just to keep me going after I was reduced to reading the back of tomato ketchup bottles just to stay sane. And then the first thing I read from his delivered collection was the incredibly cheery Maus.)

Has anyone else read this Bone thing? If you have, did you enjoy it? If you didn’t, did you keep reading anyway? I feel guilty if I abandon a book. Something about erudition. But if I didn’t read then I’d have to read Twitter all day instead and I’d go out of my mind.

(Yeah, yeah, go outside and enjoy the sunshine. Whatever.)

Did you know that Wikipedia does ISBN searches? Oh, you did. OK.

It’s a purple world

All the maps you see of the US election results are sharply divided into blue states and red states. It occurred to me that since “a state goes for Obama” sometimes means “by nine votes”, that it might be interesting to see a sort of representative map. So, the purple map of US election results:

The whole country’s pretty similar in colour, innit? I suppose this is what Obama was talking about with the “I’ll be your president too” stuff…

(map from wikimedia (svg), election results from Google, map as SVG, script to generate map)

Drunk in charge of lyrics

Hrm. Just back from the pub, where they played a song which I thought was called “Fool Out Of Me”. The video had a band all of whom wore suits, and a succession of female singers who, in the video, were reading the lyrics from a piece of paper, one at a time. Anybody got any idea what it is?