Relative Paths and On-Demand Calls in Gadgets

A problem with the current opensocial gadget spec is that there’s no relative path support. This means you end up hard-coding any references to Javascripts, CSS stylesheets, images, and services which are distributed along with your gadget.

This is not good. For example, you may have a “prod” setup and a “dev” setup. While developing, you will have to hard-code <script> tags and so on to hit the “dev” location, but then for production, you will want them pointing at your scripts in the production location. Likewise, you might want to ship the bundle to someone else for them to host on their own network.

You can deal with it using a pre-compiler tool – you know, using sed-like token substitution to piff in the right location. But a pre-compilation step is a messy compromise – I just want to distribute the code and be done with it. Another solution would be to output the gadget spec from a script, which would let you solve the problem in one of two ways: (a) inline common Javascripts and stylesheets so that you don’t even need to link to them; (b) piff in the right location on the fly. Again, this is not ideal. It introduces a new server-side language and demands the spec server supports it. My aim here is simple distribution of gadgets – as long as you can host a tree of static files, you can serve my gadgets.

The optimal solution right now is far from ideal, but is the best way I know to do it. You use On-Demand Javascript (and on-demand CSS and on-demand <insert resource type here>). First, you work out the gadget spec location, then you manipulate the URL to find the required Javascript, and then you pull it down using DOM manipulation.

I’m using a compressed version of something like this:

< view plain text >
  1. var gadgetURL = _args()["url"];
  2.     function loadScript(scriptURL, onLoaded) {
  3.       var baseURL=gadgetURL.replace(/[a-zA-Z0-9_]+.xml(?.*)?/,"")
  4.       if (scriptURL.indexOf("http")!=0) scriptURL = baseURL + scriptURL;
  5.       if (debugMode) scriptURL+="?" + (new Date()).getTime();
  6.       var script = document.createElement("script");
  7.       script.src = scriptURL;
  8.       if (onLoaded) script.onload = onLoaded;
  9.       document.body.appendChild(script);
  10.     }

It’s partly based on a mailing list comment from Arne Roomann-Kurrik. Massaging further, I end up with the following boilerplate block which must be cut-and-paste into each gadget to bootstrap reuse:

< view plain text >
  1. _IG_RegisterOnloadHandler(function() { var script = document.createElement("script"); script.src = _args()["url"].replace(/[a-zA-Z0-9_]+.xml(?.*)?/,"") + "../core.js"; script.onload = initialise; document.body.appendChild(script); });

After dropping this at the bottom of my gadget, I know that (a) ../core.js will be pulled down and executed – it is relative path from wherever the gadget came; (b) initialise() will be called once core.js has been loaded. Each of my gadget’s has an initialise() function which does gadget-specific initialisation. core.js is a common library and also happens to include loadScript() in case I want to pull down further Javascripts, and also loadStylesheet() so I can grab a stylesheet with relative path.

All this is not at all ideal, for several reasons:

  1. For all the benefit of neatly using a separate Javascript file, you have to cut-and-paste boilerplate code into every page! But at least the boilerplate won’t have to be changed often.
  2. Performance will suffer as the script is loaded later than it should be.
  3. It relies on the “url” being passed into the gadget; to my knowledge, this is not something you can definitely assume will happen, i.e. it’s not mandated by the opensocial standard that the gadget receives a parameter called “url” identifying where the gadget came from.

I have requested on the opensocial spec mailing list to provide direct relative path support and the response has been positive, hopefully we’ll see it soon, thus rendering large parts of this post obsolete. The solution looks to be rather neat – injecting a <base> tag to establish a base URL which all relative paths work against.

World timezone data

Writing a multi-timezone clock gadget, I found myself needing to convert timezones in Javascript. This is one uncharted area in Ajax/Javascript – unfortunately, there is no timezone library to my knowledge. Unfortunately, there’s no public JSON service to tell you what time it is right now in Tokyo either. I could create one without too much difficulty, but I’m aiming to build a self-contained gadget, which means I want it all in Javascript.

Back to first principles, ZoneInfo is incredibly thorough, but that makes it difficult to use for a single gadget. There is a wikipedia list too, but not easily parsed. (If web 3.0 is all about the semantic web, then wikipedia will hopefully become a better home for structured data too.) I then found “City Time Zones” which is a user-generated, wiki-style, approach. The problem is it doesn’t handle daylight savings, but it will do for now – the user will simply get a checkbox to say if it’s daylight savings or not. Yeah it’s a really ordinary solution, but the only one I can manage if I’m to build the gadget in a day or so.

I extracted from the ZoneInfo a simple list you might find useful. The first iteration is sorted by timezone and I’ve junked geo and other info, so you just have the timezone names, the offset, and major locations.

Tonga Standard Time,+13:00 Nuku’alofa
Kamchatka Standard Time,+12:00 Kamchatka
Fiji Standard Time,+12:00 Fiji, Marshall Is.
New Zealand Standard Time,+12:00 Auckland, Wellington
Norfolk Island Standard Time,+11:30 Norfolk Island
Central Pacific Standard Time,+11:00 Solomon Is., New Caledonia
Magadan Standard Time,+11:00 Magadan
Vladivostok Standard Time,+10:00 Vladivostok
Tasmania Standard Time,+10:00 Hobart
West Pacific Standard Time,+10:00 Guam, Port Moresby
AUS Eastern Standard Time,+10:00 Canberra, Melbourne, Sydney
E. Australia Standard Time,+10:00 Brisbane
AUS Central Standard Time,+09:30 Darwin
Cen. Australia Standard Time,+09:30 Adelaide
Yakutsk Standard Time,+09:00 Yakutsk
Korea Standard Time,+09:00 Seoul
Tokyo Standard Time,+09:00 Osaka, Sapporo, Tokyo
Ulaanbaatar Standard Time,+08:00 Ulaanbaatar
Taipei Standard Time,+08:00 Taipei
W. Australia Standard Time,+08:00 Perth
Singapore Standard Time,+08:00 Kuala Lumpur, Singapore
North Asia East Standard Time,+08:00 Irkutsk
China Standard Time,+08:00 Beijing, Chongqing, Hong Kong, Urumqi
North Asia Standard Time,+07:00 Krasnoyarsk
SE Asia Standard Time,+07:00 Bangkok, Hanoi, Jakarta
Myanmar Standard Time,+06:30 Rangoon
Sri Lanka Standard Time,+06:00 Sri Jayawardenepura
Central Asia Standard Time,+06:00 Astana, Dhaka
N. Central Asia Standard Time,+06:00 Almaty, Novosibirsk
Nepal Standard Time,+05:45 Kathmandu
India Standard Time,+05:30 Chennai, Kolkata, Mumbai, New Delhi
West Asia Standard Time,+05:00 Islamabad, Karachi, Tashkent
Ekaterinburg Standard Time,+05:00 Ekaterinburg
Afghanistan Standard Time,+04:30 Kabul
Caucasus Standard Time,+04:00 Yerevan
Tbilisi Standard Time,+04:00 Tbilisi
Baku Standard Time,+04:00 Baku
Arabian Standard Time,+04:00 Abu Dhabi, Muscat
Iran Standard Time,+03:30 Tehran
E. Africa Standard Time,+03:00 Nairobi
Russian Standard Time,+03:00 Moscow, St. Petersburg, Volgograd
Arab Standard Time,+03:00 Kuwait, Riyadh
Arabic Standard Time,+03:00 Baghdad
Turkey Standard Time,+02:00 Turkey
Israel Standard Time,+02:00 Tel Aviv, Jerusalem
Syria Standard Time,+02:00 Syria
Jordan Standard Time,+02:00 Jordan
FLE Standard Time,+02:00 Helsinki, Kyiv, Riga, Sofia, Tallinn, Vilnius
South Africa Standard Time,+02:00 Harare, Pretoria
Egypt Standard Time,+02:00 Cairo
E. Europe Standard Time,+02:00 Bucharest
Lebanon Standard Time,+02:00 Beirut
GTB Standard Time,+02:00 Athens, Beirut, Istanbul, Minsk
W. Central Africa Standard Time,+01:00 West Central Africa
Central European Standard Time,+01:00 Sarajevo, Skopje, Warsaw, Zagreb
Namibia Standard Time,+01:00 Namibia
Romance Standard Time,+01:00 Brussels, Copenhagen, Madrid, Paris
Central Europe Standard Time,+01:00 Belgrade, Bratislava, Budapest, Ljubljana, Prague
W. Europe Standard Time,+01:00 Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna
GMT Standard Time,+0:00 Dublin, Edinburgh, Lisbon, London
Greenwich Standard Time,+0:00 Casablanca, Monrovia
Azores Standard Time,-01:00 Azores
Cape Verde Standard Time,-01:00 Cape Verde Is.
Mid-Atlantic Standard Time,-02:00 Mid-Atlantic
Argentina Standard Time,-03:00 Argentina
E. South America Standard Time,-03:00 Brasilia
SA Eastern Standard Time,-03:00 Georgetown, South America Eastern Time
Greenland Standard Time,-03:00 Greenland
St Pierre and Miquelon Standard Time,-03:00 St Pierre and Miquelon
Uruguay Standard Time,-03:00 Uruguay
Newfoundland Standard Time,-03:30 Newfoundland
Atlantic Standard Time,-04:00 Atlantic Time (Canada)
Falkland Islands Standard Time,-04:00 Falkland Islands
SA Western Standard Time,-04:00 La Paz
Paraguay Standard Time,-04:00 Paraguay
Pacific SA Standard Time,-04:00 Santiago
Venezuela Standard Time,-04:30 Venezuela
SA Pacific Standard Time,-05:00 Bogota, Lima, Quito
Cuba Standard Time,-05:00 Cuba Standard Time
Eastern Standard Time,-05:00 Eastern Time (US & Canada)
US Eastern Standard Time,-05:00 Indiana (East)
Central America Standard Time,-06:00 Central America
Central Standard Time,-06:00 Central Time (US & Canada)
Mexico Standard Time,-06:00 Guadalajara, Mexico City, Monterrey
Guatemala Standard Time,-06:00 Guatemala
Honduras Standard Time,-06:00 Honduras
Canada Central Standard Time,-06:00 Saskatchewan
US Mountain Standard Time,-07:00 Arizona
Mexico Standard Time 2,-07:00 Chihuahua, La Paz, Mazatlan
Mountain Standard Time,-07:00 Mountain Time (US & Canada)
Pacific Standard Time,-08:00 Pacific Time (US & Canada); Tijuana
Alaskan Standard Time,-09:00 Alaska
Hawaii-Aleutian Standard Time,-10:00 Adak
Hawaiian Standard Time,-10:00 Hawaii
Samoa Standard Time,-11:00 Midway Island, Samoa
Dateline Standard Time,-12:00 International Date Line West

Yes, Tonga is 13 hours of UTC and 25 hours ahead of those little-known places that are UTC-12. In fact, Kiribati Istland (not shown here) is +14 so a day and 2 hours ahead of the others. This wasn’t meant to be easy.

Anyway, I simplified the list further to:

+13:00 Tonga
+12:00 Auckland, Wellington, Fiji, Marshall Is., Kamchatka
+11:30 Norfolk Island
+11:00 Solomon Is., New Caledonia, Magadan
+10:00 Canberra, Melbourne, Sydney, Brisbane, Hobart, Guam, Port Moresby
+09:30 Darwin, Adelaide
+09:00 Seoul, Yakutsk, Osaka, Sapporo, Tokyo
+08:00 Taipei, Ulaanbaatar, Perth, Kuala Lumpur, Singapore, Irkutsk, Beijing, Chongqing, Hong Kong, Urumqi
+07:00 Bangkok, Hanoi, Jakarta, Krasnoyarsk
+06:30 Rangoon
+06:00 Sri Jayawardenepura, Astana, Dhaka, Almaty, Novosibirsk
+05:45 Kathmandu
+05:30 Chennai, Kolkata, Mumbai, New Delhi
+05:00 Islamabad, Karachi, Tashkent, Ekaterinburg
+04:30 Kabul
+04:00 Tbilisi, Yerevan, Baku, Abu Dhabi, Muscat
+03:30 Tehran
+03:00 Moscow, St. Petersburg, Volgograd, Nairobi, Kuwait, Riyadh, Baghdad
+02:00 Turkey, Tel Aviv, Jerusalem, Syria, Jordan, Helsinki, Kyiv, Riga, Sofia, Tallinn, Vilnius, Harare, Cairo, Bucharest, Beirut, Athens, Beirut, Istanbul, Minsk

+01:00 Sarajevo, Skopje, Warsaw, Zagreb, Brussels, Copenhagen, Madrid, Paris, Belgrade, Bratislava, Budapest, Ljubljana, Prague, Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna, West Central Africa, Namibia
+0:00 Dublin, Edinburgh, Lisbon, London, Casablanca, Monrovia
-01:00 Azores, Cape Verde Is.
-02:00 Mid-Atlantic
-03:00 Argentina, Brasilia, Georgetown, South America Eastern Time, Greenland, Uruguay
-03:30 Newfoundland
-04:00 Atlantic Time (Canada), Falkland Islands, La Paz, Paraguay, Santiago
-04:30 Venezuela
-05:00 Eastern Time (US & Canada), Bogota, Lima, Quito, Havana
-06:00 Central Time (US & Canada), Central America, Guadalajara, Mexico City, Monterrey, Guatemala, Honduras, Saskatchewan
-07:00 Mountain Time (US & Canada), Arizona, Chihuahua, La Paz, Mazatlan
-08:00 Pacific Time (US & Canada), Tijuana
-09:00 Alaska
-10:00 Hawaii, Adak
-11:00 Midway Island, Samoa
-12:00 International Date Line West

Also available in cut-and-paste form

It’s free and open for a reason!

Just as I was writing this post on ignorance of open source models, there was news of a major publisher making a print edition of Wikipedia. This led to backlash reactions which illustrate exactly the kind of misunderstanding that arises when people don’t get open-source licenses (via ReadWriteWeb.

The whole point of Wikipedia is to provide a voluntary online source of information. That is why people voluntarily gave up some of their time to write the articles for free in the first place. It is a noble project, the writer believed in the project and so they participated in it. Had they known that Wikipedia would then use their work in a commercial printed venture, I’m sure they would have had second thoughts about writing those articles. At the very least they would have demanded a contract and perhaps a guarantee of financial compensation later.

Now the author might well have a point – maybe people don’t know what they’re doing when they’re adding to wikipedia and maybe wikipedia should make it more clear. Still, I find it worrying that they would consider some big ball of wrong has been cast upon them. A great place for them to start researching would be the GNU article on wikipedia, the one article whose authors knew they would be victims right from the start ;).

There are several disturbing things about this:

  • First, if this ignorance does exist, that’s unfortunate. If anyone is a major enough contributor to wikipedia to care about this, they really ought to familiarise themselves with the basics of the GNU license they’re operating under. (And for the record, I think it’s a shame wikipedia uses GNU instead of a more permissive license.)
  • It’s scarcity mentality. Boo-hoo, the publisher is making money and I’m not, so they must be ripping me off. Yeah right! If you were willing to contribute to wikipedia before, your content remains just as available online as before. What’s changed? Nothing, except someone else is going to make your content more digestible in certain contexts and accessible to more people. And yes, they will make money from it. Maybe they’ll make lots of money. Whatever. That’s what happens in a modern knowledge economy – people like Larry and Sergey make money without denying it from someone else. Far from removing others’ assets, they actually add value to everyone else. Likewise, the existence of a print wikipedia will also add, in its own way, to society’s wealth. (Although not the forests. That’s a separate, more legitimate, argument.)
  • There’s an old psychology result that says people care more about their spending power in relative terms than absolute terms. ie you ask them “Would you rather earn $50,000 a year while other people make $25,000, or would you rather earn $100,000 a year while other people get $250,000? Assume price of service and goods would remain the same.” People would rather earn half as much, if it means they are richer rather than poorer than others. That result says a lot for this kind of irrational backlash against anyone who might cash in on their “volunteer” work.
  • It’s hardly the first time this has happened. and hundreds of fairly useless SEO sites have been profiting from wikipedia content for years. I’m surprised it took this long for someone to do it. I could imagine countless opportunities for books on niche content – bizarre trivia, country almanacs, movie guides, etc etc.

That a company can do something like this without having to formally negotiate with the wikipedia foundation and a million contributors…I call that a cause for celebration, not outrage. Personally, I’ve contributed various boring tidbits to wikipedia and I hereby invite any publisher to print what they want from my contributions, even if there’s only limited demand for hard copy about snowclones.

Models of Open Source

Controversy arose in several open source projects last week: Ext JS, SpringSource App Platform, and the SWF/FLV specs. Dion has a good summary and concludes with a reminder that most people could care less:

Finally, I know that 99% of the developers out there may not even care, let alone users. There are open source wonks who like to argue about licensing and methodologies. As I watched the John Adams HBO series, I felt a little like those fine chaps arguing over the finer details of things. Many of the people didn’t know what was going on there, or why a particular Article was written the way it was. But, they had drastic implications for the people. I think that the same can hold here for some of the projects.

Now this ignorance of open source models in my experience and an interesting phenomenon. It took open source until around the middle of this decade for even the basic definition of open source to be understood, and to some extent, accepted, by mainstream IT and business communities. That’s about five decades after the practice began, two decades after Stallman’s GNU Manifest, and almost a decade after Raymond et al declared “Open Source” teh nu k00lness.

The basic definition of open source is understood, but as Dion notes, most people have no idea how the models vary, or what the implications are. Which is unfortunate, because the commercial implications are indeed vast.

I consider myself an expert on this topic ;P because I once picked up a copy of an O’Reilly book on open source models at a heavily reduced price and flicked through it intensely for at least two hours. Okay, so not quite an expert (!), more an armchair ignoramus, but certainly a stakeholder as both a consumer and publisher of open-source. And I’m hardly the Richard Stallman of the Ajax world either, but whenever I publish software that could potentially be used or adapted by someone, I make the tiny effort of including a license notice. Sometimes it almost seems arrogant to do so when the software is so trivial, but I’d rather do that than leave the license unstated, in which case it would come under the silly default, i.e. standard restrictive copyright. (Even if you agree with standard copyright, doesn’t it seem silly that rights to anything anyone creates belongs to them by default, and for the greater part of a century?)

Well, since I include a notice, I’ve had to think about which license to use.

In my dim-witted view of models, there are three key categories. All allow people to use it free of charge and generally remove any liability from the provider. They vary in what happens when people change it:

  • Copyleft/Viral (e.g. GPL, Creative Commons Share-Alike) – Anyone who modifies it must release the modified version.
  • Permissive (e.g. MIT, BSD, Apache) – You don’t have to release your modifications, though you still have some restrictions such as retaining the original license and author details.
  • Public Domain – Anything goes.

There are other distinctions too, e.g. around charging and attribution to the original creation; but the above distinction is the most important in most cases. And this is the sad thing: most IT and business people simply don’t understand these distinctions and the implications they have.

You can argue about ethics until you’re blue in the face, but the reality is, there’s no absolutely “right” or “wrong” model. It’s just horses for courses and being aware of the implications. Personally, I do have a hard time justifying copyleft-style licenses and I sometimes wonder how many people release stuff as GNU just because they associate it with open-source, without realising the full implications. I’ve worked in many commercial situations where GPL is unacceptable and I hate the idea that developers will be in the same situation as me, i.e. gleefully eyeing something that would scratch their itch, but not being able to use it. Incidentally, Ajax Patterns was initially released with the more permissive Creative Commons license, but following the book deal, O’Reilly asked me to change it to share-alike as it discourages other publishers from publishing their own version of the same book, which has apparently happened in the past. This is similar to the reason some companies release dual licenses – GPL and standard copyright. It means anyone can use it for free under GPL, but other companies can’t update and re-distribute for a fee. I can see that. It creates an incentive to release as open-source.

It’s convenient for me to have a default license choice, so I don’t have to think too hard whenever I release something. I have chosen The MIT License because it is extremely concise, and is basically the smallest (in words) mainstream license that satisfies my main aims: To allow people to work with it freely and free of the restrictive burden GNU creates; to receive credit for my work; to be free of liability. The three paragraph license can easily be embedded in any source file, which is great for releasing one-file libraries without having to include a separate README or LICENSE file. Best of all, it’s easy to grok. If developers should be able to consume open source as easily as pulling out books from a shelf, you really don’t want to release software under a license that only a lawyer could love. Don’t let MIT’s concise nature fool you into thinking it’s only used for toy projects: MIT is used in Rails, Mono, and the system for which it was originally written: X-Windows.

The MIT License looks like this:

Copyright (c)

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.