as days pass by, by Stuart Langridge http://www.kryogenix.org/days scratched tallies on the prison wall Fri, 03 Jul 2009 00:58:36 +0000 http://wordpress.org/?v=2.8 en hourly 1 Not blocking the UI in tight JavaScript loops http://www.kryogenix.org/days/2009/07/03/not-blocking-the-ui-in-tight-javascript-loops http://www.kryogenix.org/days/2009/07/03/not-blocking-the-ui-in-tight-javascript-loops#comments Fri, 03 Jul 2009 00:55:54 +0000 sil http://www.kryogenix.org/days/?p=1771 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.

]]>
http://www.kryogenix.org/days/2009/07/03/not-blocking-the-ui-in-tight-javascript-loops/feed 16
Why not to use domain sockets for a desktop CouchDB http://www.kryogenix.org/days/2009/06/26/why-not-to-use-domain-sockets-for-a-desktop-couchdb http://www.kryogenix.org/days/2009/06/26/why-not-to-use-domain-sockets-for-a-desktop-couchdb#comments Fri, 26 Jun 2009 09:47:28 +0000 sil http://www.kryogenix.org/days/?p=1769 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.

]]>
http://www.kryogenix.org/days/2009/06/26/why-not-to-use-domain-sockets-for-a-desktop-couchdb/feed 8
Using CouchDB to store contacts http://www.kryogenix.org/days/2009/06/19/using-couchdb-to-store-contacts http://www.kryogenix.org/days/2009/06/19/using-couchdb-to-store-contacts#comments Fri, 19 Jun 2009 11:51:20 +0000 sil http://www.kryogenix.org/days/?p=1761 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).

]]>
http://www.kryogenix.org/days/2009/06/19/using-couchdb-to-store-contacts/feed 7
Filmage http://www.kryogenix.org/days/2009/06/11/filmage http://www.kryogenix.org/days/2009/06/11/filmage#comments Thu, 11 Jun 2009 18:11:05 +0000 sil http://www.kryogenix.org/days/?p=1758 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…

]]>
http://www.kryogenix.org/days/2009/06/11/filmage/feed 8
Working with CouchDB http://www.kryogenix.org/days/2009/06/11/working-with-couchdb http://www.kryogenix.org/days/2009/06/11/working-with-couchdb#comments Wed, 10 Jun 2009 23:14:33 +0000 sil http://www.kryogenix.org/days/?p=1756 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!

]]>
http://www.kryogenix.org/days/2009/06/11/working-with-couchdb/feed 4
Ubuntu One beta http://www.kryogenix.org/days/2009/05/13/ubuntu-one-beta http://www.kryogenix.org/days/2009/05/13/ubuntu-one-beta#comments Tue, 12 May 2009 23:49:07 +0000 sil http://www.kryogenix.org/days/?p=1753 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.

]]>
http://www.kryogenix.org/days/2009/05/13/ubuntu-one-beta/feed 16
Absolute beginners guide to Google Maps JavaScript http://www.kryogenix.org/days/2009/05/10/absolute-beginners-guide-to-google-maps-javascript http://www.kryogenix.org/days/2009/05/10/absolute-beginners-guide-to-google-maps-javascript#comments Sun, 10 May 2009 20:47:39 +0000 sil http://www.kryogenix.org/days/?p=1750 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.

]]>
http://www.kryogenix.org/days/2009/05/10/absolute-beginners-guide-to-google-maps-javascript/feed 2
Games in pure SVG http://www.kryogenix.org/days/2009/05/09/games-in-pure-svg http://www.kryogenix.org/days/2009/05/09/games-in-pure-svg#comments Fri, 08 May 2009 23:33:47 +0000 sil http://www.kryogenix.org/days/?p=1744 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.

]]>
http://www.kryogenix.org/days/2009/05/09/games-in-pure-svg/feed 39
LugRadio Live 2009 http://www.kryogenix.org/days/2009/05/08/lugradio-live-2009 http://www.kryogenix.org/days/2009/05/08/lugradio-live-2009#comments Fri, 08 May 2009 15:22:38 +0000 sil http://www.kryogenix.org/days/?p=1741 http://www.lugradio.org/live/2009/

]]>
http://www.kryogenix.org/days/2009/05/08/lugradio-live-2009/feed 1
Auto-discoverable local websites http://www.kryogenix.org/days/2009/04/27/auto-discoverable-local-websites http://www.kryogenix.org/days/2009/04/27/auto-discoverable-local-websites#comments Mon, 27 Apr 2009 07:31:07 +0000 sil http://www.kryogenix.org/days/?p=1738 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.)

]]>
http://www.kryogenix.org/days/2009/04/27/auto-discoverable-local-websites/feed 18