Friday, 8 October 2010

CSS and showing my age

Okay. I can't be the only one. Surely some of you also have trouble remembering the order of the values in CSS shorthand properties, e.g.:

margin: 10px 20px 30px 40px;
I mean, I'm an engineering kind of guy. I'm used to coordinate systems like (top,left)-(bottom,right) or (x1,y1)-(x2,y2). CSS, however, uses neither. Instead, it's top right bottom left. I expect there's a good reason.

So showing my age, but I just could not keep that in my head. I kept thinking, "if only I understood why they'd done it, maybe I could remember it." But I've gone one better, and am showing my age ^ 2: I'll just remember "tribble".

That's right. Cute furry (and ultimately dangerous) things from Star Trek: The Original Series. "tribble" as in T R B L as in Top Right Bottom Left:

         +----------------- Top
| +------------ Right
| | +------- Bottom
| | | +-- Left
v v v v
margin: 10px 20px 30px 40px;

Sorted.

I suppose I'd be remiss if I opened this topic but didn't mention that you can also specify one, two, or three values, but the mnemonic holds well enough  basically, just remember to start with the T and you'll be okay. Specifically:

         +----------------- (All four)
v
margin: 10px;

+----------------- Top & Bottom
| +------------ Right & Left
v v
margin: 10px 20px;

+----------------- Top
| +------------ Right & Left
| | +------- Bottom
v v v
margin: 10px 20px 30px;

Right, well, as there are no computers around here to reason into a conflicted meltdown, I guess I'll head off for a Saurian brandy and see if I can chat up an Orion slavegirl. I've always been partial to scantily-clad brunettes with green skin...

Tuesday, 5 October 2010

IE6, the Undead Browser

2013/05/16: Ah, what a difference a couple of years makes. :-) Today, this article can be a lot shorter, and could be titled "IE6, the Mostly Dead Browser". Huzzah!

Is IE6 finally dead?

  • In China: No, it's still more than 24% of the browser share there.
  • Everywhere Else: Yes!

I can't give the region-by-region breakdown I could below because Net Applications have started charging (a lot) for that report, but even in places like Mexico and India, which had high IE6 use a couple of years ago, use has plummeted. According to ie6countdown, after China, Taiwan is next at 3.5%, followed by India at 2.8%, and then Japan and Russia tied at 1.7%. The corporate U.S. finally "got" the security risk and has moved on to IE8 or IE9.

The take-away? If you're developing web pages and web apps for China, you must still support and test on IE6. By all means include an educational banner or something advocating change, but you must still support it. Just about anywhere else, fergedabouddit.

And what about IE7? Great new there: Worldwide usage of IE7 is currently just 1.81%. So people leaving IE6 jumped to IE8 (23.08%) or IE9 (18.17%) (and those nearly 20% at one point who were using IE7 have moved on too). We can figure a lot of those IE9 users will soon be on IE10. The IE8 users will be with us for a while, since that's as high as Windows XP goes.

Here's the old article from October 2010 (with updates in November 2010 and March 2011), just for posterity:


2011/03/14: See also Microsoft's new IE6 countdown site

2010/11/18: Updated to also reference StatCounter's figures (for May 2010).

There's a common refrain on sites where people ask for help getting things to work well cross-browser, when someone mentions needing to support IE6:

IE6 is dead. Microsoft officially stopped supporting it. I don't see any reason you should.

— comment from a StackOverflow user

IE6 is dead. don't speak of it.

— another StackOverflow comment

Some people have even held a funeral for it (Microsoft were classy enough to send flowers); others declare it Well and Truly dead.

So is IE6 finally dead?

No.

Far from it, IE6 is still (as of this writing) the third most used browser out there, at 15.55% it's just barely behind Firefox 3.6 at 17.05%, both trailing IE8 at 29.06%. (That link is for September 2010; current stats here.) StatCounter gives a slightly lower figure, making it the fourth most popular browser in the world at 9.75% in May 2010 —which makes sense; StatCounter and Net Applications have different customer bases.

Like most developers who do browser-based applications, I wish IE6 were dead. It certainly should be, and Microsoft are doing everything they can to kill it, but unfortunately it's not quite that simple. IE6 was the de-facto standard browser in large corporate and government environments for the majority of the boom of browser-based applications, and therein lies the problem. Large organizations are very slow to upgrade key bits of software. For example, many of us recently petitioned the UK Government to upgrade all government departments away from IE6. Their response was to say that it's "...not straightforward for HMG departments to upgrade IE versions on their systems...", that testing their web apps for compatibility "...can take months at significant potential cost to the taxpayer..." and that they deal with the security issues with firewalls and malware scanners. Big business is much the same as big government in this regard. You can bet that the majority of users of IE6 are sitting in a cubicle somewhere.

It's also interesting to try to find a statement from Microsoft backing up the assertion from our first commenter above that IE6 is no longer supported by Microsoft. Some point to the Lifecycle Supported Service Packs page saying that it says IE6 support ended on July 13th, 2010, but that page is about service packs, not products, and the July 13th date is only listed next to some of them; others, like the one for IE6 on Windows XP SP3 say that support ends 24 months after the next service pack is released. There hasn't been an SP4 for XP and SP3 is still supported (support for SP2 ended on the aforementioned July 13th), so... Further, that page also (now) says it's "no longer updated and scheduled for retirement," referring people to the Microsoft Product Lifecycle Search page instead. Amusingly (or perhaps I'm just laughing to hide the tears), if you use that page to find lifecycle information for Internet Explorer 6, it doesn't give an end date for extended support; instead, it says "For support dates for specific Internet Explorer 6 and operating system versions and their service packs, visit the Lifecycle Supported Service Packs site at..." Yup, that's right, they then give our first link above, the one that says it's no longer maintained. Rinse, repeat. So has Microsoft ended support for IE6? If so, those pages aren't saying so.

So what does this mean for those of us who develop web sites and applications? Well, your first thought might be that if you're writing a consumer-facing website, you can probably drop support for IE6. And that's probably mostly true, although you have to consider what it could mean to lose people browsing on their lunch break (or any time the boss isn't around) when most sites are scratching for every hit they can get, antiquated insecure non-compliant browser or no. You also have to consider where your visitors are coming from; StatCounter says that IE6 use is half as likely in the U.S., Europe, the UK, Canada, Australia, and New Zealand, where in all of those except Australia they're seeing numbers under 5% and in Australia only just barely over (as compared with 9.75% worldwide). But even StatCounter is seeing IE6 as the second-most popular browser in Asia at 20% and the top browser in Africa at 22%. So the locality (if any) and language of your site play a part.

But even in those ~5% countries, if you're building software that you want corporations to be able to adopt, I'd say that right now, today, you ignore IE6 support at your peril. Unfortunately. Maybe in another year, although with the downturn, IT budgets are pretty tight...it may take even longer than that.

There is good news, though. This time last year (September 2009), IE6 was the number one browser, at 24.42% dominating IE7's 19.39% and IE8's 16.84%. So clearly on the way out. I predict the decline will continue but flatten out as we hit the hard core corporate deployments with strapped IT budgets. (The other good news in comparing last year to this year is how IE7 is being displaced by IE8. Excellent. IE8 is a much, much better browser than either IE6 or IE7...and if people are willing to upgrade, when the time comes maybe they'll keep going to IE9.)

Happy coding.

Tuesday, 21 September 2010

A literal improvement

JavaScript literals are getting better. Until recently, the grammar for object literals didn't explicitly allow a trailing comma, like this:

var obj = {
foo: 42,
bar: 27, // <== This is the problem
};
SpiderMonkey (Firefox), V8 (Chrome), and whatever Safari and Opera use don't care, but JScript (IE) prior to JScript 6 (IE8) throws a parsing exception on the comma and your script dies. (JScript 6 / IE8 fix this.)

A trailing comma in an array literal has a different issue:
var a = [1, 2, 3, ];
All versions of JScript so far (including JScript 6 / IE8) create an array with four (yes, four) entries, the last of which is undefined. This isn't unreasonable, because the spec wasn't explicit about it and we were always allowed to have blank entries (e.g., var a = [1, , 3];) and those entries defaulted to undefined — but everyone else went the other way and created an array with three entries instead.

Fortunately, ECMAScript 5 clears this up. The trailing comma is explicitly allowed in object literals (Section 11.1.5), and in array literals (Section 11.1.4). In the case of array literals, the trailing comma doesn't add to the length of the array (a.length above is 3).

The team behind IE9 are very engaged with standards bodies now, so hopefully that includes the JScript folks and they'll change the array behavior, though you know it must be a much harder sell for them than the object literal was — it involves changing the behavior of something that did work. Still, here's hoping.

Sunday, 19 September 2010

Don't Default Destroy

Here's a little tidbit for UI designers: Don't default to destroying things. You'd think that would have been obvious, no?

No. VirtualBox is an excellent virtualization environment, one of the best in the world and possibly a contender for the top spot. But the default UI has a big UI fault.

VirtualBox, like most good VM technologies, lets you take "snapshots" of VMs that you can then restore, going back in time. Very, very handy for when you're about to do a tricky update and want to be able to roll it back.

In my case, the tricky update hard-crashed the box, which means I had to use the handy Machine | Close to terminate the VM. And lo! The Machine | Close dialog box has a handy tickbox for "Restore most recent snapshot". So I ticked the box, and it worked a treat. I went ahead and kept using the VM for several days.

Then something unrelated made the VM crash, and I did a quick Machine | Close. The next time I fired up the VM, something seemed wrong — files were missing, configuration changes I made a while back were undone, something was amiss!

You guessed it: The Machine | Close dialog box had remembered the "restore last snapshot" setting and so VirtualBox happily destroyed my data.

Should I have noticed the tickbox was ticked? Yes, but it's one UI element of about eight on that window, and the penalty for failing to notice it is unacceptably high. If I had just ticked the box, I could see not asking for confirmation — but not when the box was ticked by default.

Amazingly, this very thing was pointed out in a bug report, and the report was closed as "fixed" when they added the ability to have VMs override defaults if you explicitly set that up.

Um. Yeah. Because that addresses the usability problem. If you know you might make this mistake in the future, you can go update each and every VM you have to make it impossible to use that feature of the dialog box. And then remember to do it for all VMs you create in the future. All because some UI designer wants the purity of either remembering all the options on the dialog, or none of them. I don't think so.

So I've opened a new bug report on it. Hopefully they'll see this as the bug it is, but the point of this post is: Don't destroy things by default, you're likely to piss people off.

Thursday, 16 September 2010

Double-take

There's an issue with Microsoft's JScript interpreter (the one used by IE, Windows Scripting Host, and others) that you see mentioned deep in discussions of other things. I thought it would be worth just briefly talking about on its own.

Update: The newer version of JScript used by IE9 and up doesn't have this bug anymore. Yay! Still in IE8 and earlier, though.
Basically, if you use a named function expression in your JavaScript code, JScript will process it twice, creating two separate function objects, at two separate times: First it treats it as though it were a function declaration (even though it isn't), and then it treats it as the expression it is. This is not a distinction without a difference, either, as we'll see below. (Amongst other things, it creates "symbol bleed," putting the function's name in the enclosing scope in clear violation of Section 13 of the specification, which says that it should only be defined within the function's own scope).

What do I mean by function declaration vs. function expression (named or otherwise)? Here's a function declaration:
function foo() {
}
Here's an anonymous function expression:
var foo = function() {
};
And here's a named function expression — this is the one JScript (IE) has an issue with:
var f1 = function foo() {
};
The easiest way to tell whether you have a declaration or an expression is to ask yourself: Are you using it as a right-hand value? E.g., are you assigning it to a variable/property or passing it into a function as an argument? If so, it's an expression. If it's standalone, it's a declaration. Here are some further examples of named function expressions:
bar(function foo(){});

var obj = {
nifty: function foo() {
}
};
So first off, how do we know JScript is creating two function objects? Here's the easiest way:
var f1 = function foo() {
alert(f1 === foo); // alerts "false" on IE, "true" on other browsers.
};
f1();
So, okay, but what do we care? Well, let's say you want to hook up an event handler and have it unhook itself later if some condition is met:

Prototype example:
$('foo').observe('click', function fooClickHandler() {
if (/* ...some condition... */) {
this.stopObserving('click', fooClickHandler);
}
});
jQuery example:
$('#foo').click(function fooClickHandler() {
if (/* ...some condition... */) {
$(this).unbind('click', fooClickHandler);
}
});
Perfectly reasonable, but won't work on IE. The handler will remain attached, because when you unhook a specific event handler, the function reference you give has to be the same as the reference you want to remove. On IE, the above, it isn't: fooClickHandler isn't the same function that we hooked up. The expression returned a different function.

So how do you work around it? Just make sure you're using declarations, like this:

Prototype example:
function fooClickHandler() {
if (/* ...some condition... */) {
this.stopObserving('click', fooClickHandler);
}
}
$('foo').observe('click', fooClickHandler);
jQuery example:
function fooClickHandler() {
if (/* ...some condition... */) {
$(this).unbind('click', fooClickHandler);
}
}
$('#foo').click(fooClickHandler);
If you don't want fooClickHandler to be a symbol in that scope, wrap it up in a scoping function, like so:

Prototype example:
(function() {
function fooClickHandler() {
if (/* ...some condition... */) {
this.stopObserving('click', fooClickHandler);
}
}
$('foo').observe('click', fooClickHandler);
})();
jQuery example:
(function() {
function fooClickHandler() {
if (/* ...some condition... */) {
$(this).unbind('click', fooClickHandler);
}
}
$('#foo').click(fooClickHandler);
})();
Alternately, you could just not use names (and use arguments.callee to unhook the handler), but there are lots of good reasons not to do that (arguments.callee is slow on most browsers, not allowed in ECMAScript's new "strict" mode, and besides, names are good).

So what's this "symbol bleed" issue I mentioned? Well, according to the specification, the scope of the function name in a function expression is confined to the function itself, not the encompassing scope. So:
var f1 = function foo() {
// `foo` is defined here
};
// but not here
Whereas, of course, if that were a function declaration, the foo symbol would (of course!) be defined in the scope in which the function is declared.

(You can see this coming, can't you?) Since one of the times IE processes the named function expression it treats it as a declaration, it incorrectly defines the symbol in the enclosing scope — much like we would do if we didn't use the scoping functions above — which is incorrect.

Happy coding!

Sunday, 12 September 2010

Boot, Ubuntu, boot! Good dog!

This isn't about writing software, but it's a snippet, so...

I have a fresh new desktop based on the Intel DH57JG board on which I've happily installed Ubuntu 10.04 LTS desktop. Aside from a video mode detection issue, things are great, but I had an odd symptom: Ubuntu could successfully shut down and power off, but it would crash if I asked it to reboot. Just an annoyance, but surprisingly...annoying.

So naturally I consulted a Major Search Engine(tm)(r), and while I found several threads related to this problem, I never found one where the original questioner actually said their had been solved. I did find one where someone chimed in with "When I had that problem, adding reboot=bios to the kernel options fixed it." So I tried that, but no go. I also found a thread where someone said "I've tried the reboot b, c, and h options but..." So I figured there had to be more options for this reboot thing than just "bios" or none.

Well, it took some digging and installing the linux source (which is nicely packaged, so not like that's hard), and my machine now happily reboots when I ask it to. Because the options for reboot are a bit hard to find, here they are (for the x86 architecture) as of the Linux kernel 2.6.32-24:

warmDon't set the cold reboot flag
coldSet the cold reboot flag
biosReboot by jumping through the BIOS (only for X86_32)
smpReboot by executing reset on BSP or other CPU (only for X86_32)
tripleForce a triple fault (init)
kbdUse the keyboard controller. cold reset (default)
acpiUse the RESET_REG in the FADT
efiUse efi reset_system runtime service
pciUse the so-called "PCI reset register", CF9
forceAvoid anything that could hang.
(If you're curious, the answer in my case was reboot=acpi. At least, that was the first one I tried that worked, so I stuck with that.)

If you need a more up-to-date list, or a list for a different architecture, here's how I got that:
  1. I installed the linux-source package, which dumps a bzip2'd source tarball in /usr/src

  2. Uncompressed and untarred the tarball

  3. Looked at the arch/[architecture]/kernel/reboot.c file. Since I'm on an x86 processor on the 2.6.32 kernel, the full path in my case was /usr/src/linux-source-2.6.32/arch/x86/kernel/reboot.c but of course YMMV.
(Lest you think I was terribly clever finding the options in the source, the first place I looked was in the kernel parameters documentation —/usr/share/doc/linux-doc/kernel-parameters.txt.gz — but all that said was to look in reboot.c. :-) )

I applied the change by editing /etc/default/grub, adding that to the GRUB_CMDLINE_LINUX_DEFAULT variable, running update-grub, and rebooting (er, that is, shutting down and then starting up — rebooting would have crashed, of course).

Hope this saves someone else some time.

(If the title of this post seems oddly familiar but you can't place it, here.)

Thursday, 9 September 2010

Modern Youth

My son has now unequivocally demanded his own proper computer.

My son is not yet three years old.

At this rate, by the time he's six he'll have a better StackOverflow rep than I have.