More interesting news from Amazon: Now S3 supports static website hosting on the root of your domain. So in addition to http://www.example.com you can now have http://example.com. This comes warm on the heels of their having added CORS support in August and redirections in October. The directon is fairly clear, eh?
Nifty SnippetsTM of code, techniques, and information focussing on Ajax, web scripting, and engineering.
Saturday, 29 December 2012
Tuesday, 18 December 2012
Website Feedback Popups
You want my feedback on your website? Here's my feedback: Website "feedback" popups are irritating and intrusive.
Friday, 9 November 2012
Font Size Units
I've always used points (pt
values) for sizing fonts on web pages, e.g.:
body {
font-size: 12pt;
}
Those of you who know me know that I'm a developer, not a designer (in the web designer sense; I design systems, but that's different). I couldn't visual-design my way out of a paper bag. (Okay, maybe that's a bit harsh.) I don't think I'm a one-trick pony, but I'm definitely much more left- than right-brained. The engineer in me says, I'm setting a font size, right? And fonts are measured in points, so I use points. Or at least, I used to.
Chris Coyier, on the other hand, is a designer. And he gives some good reasons even an engineer can understand why using pt
values only makes sense for print stylesheets, not screen stylesheets. And apparently he's just recently been converting himself to using ems rather than pixels. Both articles are interesting reads.
Wednesday, 31 October 2012
Blitz.io Updates Pricing Model
Early this month I was checking out blitz.io and although it looked like a cool tool (and fun), the pricing model stopped me looking at it too closely, for reasons I explained to them:
Hi folks,
Was just checking out blitz.io, which looks really cool (and fun), but I was stopped pretty early on by the pricing. I don't understand why the length of a rush is tied to the number of concurrent users (for pricing purposes). 1-minute tests are basically useless, other than checking if the site's going to just immediately fall over at a given load. I don't even trust 10-minute tests. To adequately determine the capacity of a system, I'd want to run a test for at least half an hour and ideally an hour, as the various components of the system go through their various operations (GC, for instance). I don't always need 50,000 concurrent users, but I do want the ability to choose longer rushes. Do you have a mechanism for that? If not, could I suggest you add one?
Best,
--
T.J. Crowder
Less than half an hour later (nice), Michael Smith from blitz wrote back to tell me new pricing was on the way.
Well, it's here, and it makes so much more sense: You buy credits (they start at $1 USD = 1 credit), and one credit is worth 1 minute of 1,000 concurrent users. No longer is the length of a rush tied to the number of concurrent users, you control those variables completely independently. A 20-minute rush of 1,000 concurrent users costs 20 credits. 20 minutes of 10,000 concurrent users, 200 credits. And instead of being clock-on-wall time for a set period (which apparently it used to be), you're only charged for the time the rush is actually running; if something goes wrong you can stop it early to avoid spending credits unnecessarily.
As part of this, they did discontinue their old free level in favor of topping up all accounts to 10 credits each month (even accounts that haven't bought credits). There's some discussion about what that means for their continuous integration clients, which is probably worth a read.
But fundamentally, well done blitz for listening to your customers (clearly it wasn't my note that got them working on a new model, that was just happy timing for me). Now I can take a closer look.
Wednesday, 24 October 2012
Asynchronicity
I see questions like this one a fair bit: The author has written this code (and is apparently using jQuery):
function Obj() {
this.id = 0;
this.name = '';
}
Obj.prototype.setName = function(name) {
this.name = name;
};
function init() {
var object1;
object1 = new Obj();
object1.setName("Chris");
alert(object1.name); // alerts 'Chris'
$.post('my_json_list.php', function(data) {
object1.setName(data.name);
alert(object1.name); // alerts 'John'
});
// After completing the data transfer alert the value of object
alert('After data transfer the value is: '+ object1.name); // alerts 'Chris' (!)
}
The comment at the end embodies the question: The author expects the ajax call to be complete at that point. But it isn't. That code runs after the request has been started, but before it completes. So of course object1.name
is still "Chris"
— nothing has changed it yet. The author of that code is not remotely alone in this confusion, I've answered at least a dozen questions on StackOverflow (such as this one) where this was the fundamental problem. So:
Shout it from the rooftops: Ajax calls are asynchronous. :-) (By default.)
That means the code that starts the call runs, then any code following it, and then the ajax callbacks happen some time later. E.g., here's that init
code again with some comments saying when it happens:
function init() {
// 1: First this code runs...
var object1;
object1 = new Obj();
object1.setName("Chris");
alert(object1.name); // alerts 'Chris'
// 2: ...and now this code *starts* the request...
$.post('my_json_list.php', function(data) {
// 4: (See #3 below) Then, some time AFTER #3 below, this code runs
object1.setName(data.name);
alert(object1.name); // alerts 'John'
});
// 3: ...now the request has started but is not yet finished,
// so `object1.name` remains `"Chris"`
alert('After data transfer the value is: '+ object1.name); // alerts 'Chris' (!)
}
So what to do about it? Easy, don't use the result of the call at point #3 above, use it at point #4 above.
This simple fact has an important implication: You cannot use the result of an ajax call as the return value of a function. This code is fundamentally flawed:
function getSomething(id) {
var returnValue;
$.ajax({
url: "/path/to/resource",
data: {id: id},
success: function(result) {
returnValue = result.data;
}
});
return returnValue; // WRONG
}
That's written so you can call it like this:
something = getSomething("some ID");
if (something) {
doSomethingWith(something);
}
else {
doSomethingElse();
}
The problem is, it doesn't matter what id
value you feed into doSomething
, I can tell you what its return value will be every single time: undefined
. The call to doSomething
will complete, and return the default value of returnValue
(which is undefined
), and then some time later the callback will occur and set the value of returnValue
(but it's a bit like a tree falling in the forest, as at that point no one uses it).
Can doSomething
be fixed? Yes, in two ways: We can force the ajax call to be synchronous (bad idea) or we can embrace the event-driven nature of web applications (good idea).
Let's look at that first option: We can (for now) add the option async: false
to the ajax
call (that option is deprecated — but functional — in jQuery 1.8 and will go away at some point, though not apparently in 1.9). If we do that, the call to ajax
doesn't return until the ajax call completes and its callbacks have finished. This is a bad idea because ajax calls can take significant time (even a tenth of a second is significant to human perception), and JavaScript on browsers is single-threaded. So during the time the ajax call takes, our page becomes non-responsive. (In fact, on several browsers, the entire browser — including unrelated tabs — just seems to lock up.)
Okay, so we don't want that. How do we fix it so doSomething
can return what we want it to? By making doSomething
return its result using a callback, just like ajax
does:
function getSomething(id, callback) {
$.ajax({
url: "/path/to/resource",
data: {id: id},
success: function(result) {
callback(result.data);
}
});
}
...and calling it like this...
getSomething("some ID", function(something) {
if (something) {
doSomethingWith(something);
}
else {
doSomethingElse();
}
});
Voilà, we've embraced the event-driven nature of web applications, kept our pages responsive, and it didn't even have that much impact on the calling code.
Happy (async) coding!
Thursday, 4 October 2012
I Don't Want To Create An Account
Note to online vendors:
I don't want to have to create an account to give you business.
Got it? By all means offer me the option of doing so, if that makes you happy, but if I'm buying 10 quid of lightbulbs from your site, or a one-off rail ticket, I really don't want to create a username and password, opt out of your effing mailing list, etc., etc. Imagine if you had to "create an account" with every corner store you bought £10 of stuff from.
And I really don't want to be prevented from making subsequent purchases because I can't remember the stoopid password I gave the last time you made me create an account I didn't want and your "reset your password" feature is slow/broken.
The relevant term here is "barrier to sale." If you're trying to sell things, here's a hint:
Barrier to Sale = Bad Thing(tm).
(Are you listening, National Rail?)
Wednesday, 3 October 2012
You can contribute to caniuse.com
I'm sure most of us have referred to (and probably cited) caniuse.com at some point. It's probably the most comprehensive collection of browser feature support around. Want to know the status of CORS support? Here you go.
Well, now if you spot an error or want to add further information, you can do so fairly directly: caniuse.com is now on GitHub.
I should probably note that caniuse.com is monetized (in a very minimal, unobtrusive fashion at present), and perhaps you don't want to contribute to someone else's monetized project on the theory that, well, they're getting paid for this (assuming the ads cover the hosting). Fair enough. For me, barring big changes to the site, I'd be happy to add to the data there if I happen to know something that's not covered. It's a great resource, well-managed.
(Side note: I'm not affiliated with caniuse.com in any way, something that may not be obvious from the above.)
Thursday, 27 September 2012
Quick note on RegExp#lastIndex
Just a quick note on RegExp#lastIndex
: It's misnamed. It's not the "last" index of anything, it's the index of the next character in the string that will be looked at by the regex instance's exec
function (if the regex has the global flag and exec
is used on a string that's long enough). It's 0 on freshly-created instances. Just useful to remember, if you ever need to set it explicitly (which you're allowed to do), think in terms of "next" rather than "last".
Of course, you hardly ever need to set it explicitly. The only reason I've ever done so was to work around a bug an issue in some JavaScript engines which are pretty outdated now (such as the one in Firefox 3.6, which virtually no one uses anymore). For anyone who doesn't already know about it, that issue was that some engines reused RegExp
instances defined by literals in unexpected ways, which is a problem because RegExp
instances have state (the aforementioned lastIndex
). On those engines, you get surprising results from code like this:
function test(str, expect) {
var re = /./g,
m = re.exec(str);
if (m) {
console.log("Matched: " + m[0] +
", expected: " + expect);
}
else {
console.log("No match, expected " +
(expect === null ? "no match" : expect));
}
}
test("one", "o");
test("two", "t");
If you run that code on most engines, you get the expected results. But on some engines, instead of matching "t"
on the second call to test
, the regex matches "w"
because the instance defined by the literal gets reused (the same instance is used by both calls to test
), and of course after the first call its lastIndex
is 1. The workaround was to explicitly set re.lastIndex = 0;
before calling exec
when you were starting a new set of matches, even if it looked like the instance was fresh.
Apparently there was some ambiguity in the spec (gosh) which makes this an interpretation rather than an outright bug, although I suspect I'm not the only one thinking it's pretty clear that two separate instances should be used. It was cleared up in the ES5 spec and Firefox's engine has been doing this right for a while now (since Firefox 4, I think). I expect any other older engines that had this odd interpretation have probably been fixed as well.
Wednesday, 26 September 2012
Incredible. Extraordinary. Inspiring. Beautiful.
Ten years of Hubble photographs of a tiny portion of the night sky, well away from the glare of the Milky Way, deep into the infrared and then corrected back to visible, the eXtreme Deep Field is nothing less than a breathtaking view deep into the Universe. Just...impossibly incredible.
Saturday, 1 September 2012
S3 Adds CORS Support
Thursday, 23 August 2012
A reminder how Microsoft used to drive web innovation
As IE6 finally rides into the sunset,* Nicholas C. Zakas offers us a reminder of how, in a series of browser releases culminating in IE6, Microsoft introduced many of the key web innovations we use today such as innerHTML
, access to all elements (not just forms and such), Ajax, modern events, and several others. This isn't in any way to discount what Netscape and others have done, but it's worth remembering that the browser everyone loves to hate was easily the best browser available when it came out. (Opera made a run at it soon thereafter, but never quite managed to take the lead, mostly because it didn't support legacy non-standard sites well. And then of course, along came Firefox, and then Chrome.) Good read, thanks Nicholas!
(* Unless — huge caveat — you're creating sites for China [21.3% market share], or arguably for Japan [4.7%] or India [3%].)
Tuesday, 14 August 2012
Measuring Scrollbar Size
Normally we want to avoid doing this sort of thing, but sometimes you just end up having no other option: Recently I couldn't avoid doing some sizing logic in JavaScript rather than CSS and markup, and I had to know the size of the scrollbars on specific elements. I found this post by Alexandre Gomes (which in turn was based on a MooTools forum thread; those forums are gone now), which shows a simple way to do it. I modified the code to measure both vertical and horizontal scrollbars and let you specify the element within which to measure in case the styling of that element affects the result, added some comments, and did some cleanup. Works a treat, I've tested it on a wide variety of browsers young and old with good results. Here's the code:
function measureScrollbars(container) {
var child, parent,
wWithout, wWith,
hWithout, hWith;
// Create a parent div with a fixed size
parent = document.createElement('div');
parent.style.width = "150px";
parent.style.height = "150px";
// Create a child div that's 100% of the width (granted
// that would be the default for a div) and which exceeds
// the parent's height
child = document.createElement('div');
child.style.width = "100%";
child.style.height = "200px";
// Put them in the DOM
parent.appendChild(child);
container.appendChild(parent);
// Measure the width without a scrollbar, then again with
parent.style.overflow = "hidden";
wWithout = child.offsetWidth;
parent.style.overflow = "scroll";
wWith = child.offsetWidth;
if (wWithout === wWith && "clientWidth" in parent) {
wWith = parent.clientWidth;
}
// Now make the child 100% height, and too wide
child.style.height = "100%";
child.style.width = "200px";
// Measure without scrollbar, then again with
parent.style.overflow = "hidden";
hWithout = child.offsetHeight;
parent.style.overflow = "scroll";
hWith = child.offsetHeight;
if (hWithout === hWith && "clientHeight" in parent) {
hWith = parent.clientHeight;
}
// Done
container.removeChild(parent);
return {
width: wWithout - wWith,
height: hWithout - hWith
};
}
Or if you want the jQuery-ified version:
function measureScrollbars(container) {
var child, parent,
wWithout, wWith,
hWithout, hWith;
// Create a parent div with a fixed size
parent = $('<div>').css({width: "150px", height: "150px"});
// Create a child div that's 100% of the width (granted
// that would be the default for a div) and which exceeds
// the parent's height
child = $('<div>').css({width: "100%", height: "200px"});
// Put them in the DOM
parent.append(child).appendTo(container);
// Measure the width without a scrollbar, then again with
parent.css("overflow", "hidden");
wWithout = child[0].offsetWidth;
parent.css("overflow", "scroll");
wWith = child[0].offsetWidth;
if (wWithout === wWith && "clientWidth" in parent[0]) {
wWith = parent[0].clientWidth;
}
// Now make the child 100% height, and too wide
child.css({height: "100%", width: "200px"});
// Measure without scrollbar, then again with
parent.css("overflow", "hidden");
hWithout = child[0].offsetHeight;
parent.css("overflow", "scroll");
hWith = child[0].offsetHeight;
if (hWithout === hWith && "clientHeight" in parent[0]) {
hWith = parent[0].clientHeight;
}
// Done
parent.remove();
return {
width: wWithout - wWith,
height: hWithout - hWith
};
}
Happy coding!
Wednesday, 8 August 2012
jQuery - Element cleanup update
For those who saw my jQuery - Cleaning up when elements go away post yesterday, I've updated it showing how we can do this right now, today, without waiting for the enhancement (or if the enhancement is never accepted). Oh, and the enhancement went from six lines to three. Many thanks to Dave Methvin for showing how (in both cases). Enjoy!
Tuesday, 7 August 2012
jQuery - Cleaning up when elements go away
(Updated 08/08/2012.)
Have you ever wanted to get a notification when an element is removed from the DOM so you could clean up? For instance, maybe you have events hooked on a different object (like resize
on window
) that you want to unhook when the element goes away.
Recently I wanted to, and since I know that jQuery does cleanup when elements are removed (so it can clear out event handlers and its cache for data
), I wondered if it triggers an event for us.
It doesn't, but we can still get what we want quite cleanly. I'll describe what I'm hoping we'll be able to do tomorrow, and what we can do today.
Tomorrow (I hope)
We can enhance jQuery to give us an event on cleanup — with just three lines of code and virtually no overhead. Inside jQuery's internal cleanData
function, just after the line that currently reads if ( data && data.events ) {
, we add this:
if ( data.events.jqdestroy ) {
jQuery(elem).triggerHandler("jqdestroy");
}
Boom, that's it. Now if we need notification when an element is going away, we just hook up the event:
$("selector_for_the_element").on("jqdestroy", function() {
// Do your cleanup
});
We use triggerHandler
rather than trigger
because we don't want bubbling (there's another way we can avoid bubbling, but it requires a couple more lines of code, and triggerHandler
is more efficient anyway — thanks to Dave Methvin for that!).
Here's a copy of jQuery 1.8rc1 with the patch, you can play with it here — that latter link is a test page that generates 10,000 elements, 5,000 of which we hook the click event on (so that they have something in data.events
), and two of which we hook the jqdestroy event on. Then we call html
on the container element to destroy them all and time how long it takes. You can compare that with this version using an unmodified version of 1.8rc1. For me, the times are much of a muchness (on Firefox 14, both versions average ~142ms when the jqdestroy event isn't hooked, and when it is [on two elements] the version that fires it averages ~163ms).
What I like about this is that if nothing has hooked the event, the overhead is at most one extra property check (the if ( data.events.jqdestroy )
) per element destroyed (zero overhead for elements that haven't had any events hooked at all), but it enables a completely familiar and straight-forward way to get notifications.
Well, okay, but is there really a need for it? It would seem so: jQuery UI duck-punches cleanData
so they can clean up; TinyMCE goes further, monkey-patching several API calls (empty
, replaceWith
, and others) so it can clean up an editor attached to an element. And of course, I wanted it for my plug-in that needs to unhook window.resize
if there are no more active copies of it.
Now, let me clear about something: To my mind, using this event is a last resort. It's a big hammer, and if you used it on a lot of elements, removing those from the DOM could lag a bit. Consider this example which hooks jqdestroy
on 5,000 of the 10,000 elements. For me, the elapsed times go from ~163ms when firing it on just two elements to ~450ms firing on 5,000 (again Firefox 14). Now, 5,000 is a lot of elements to hook this event (or any other) on, and anything can be abused, the point is just...don't abuse it. :-) The best use cases for this will be things like TinyMCE's editors, or grid plug-ins that need to handle resize in code, that sort of thing — where there will be only a few elements with the event hooked.
I've opened an enhancement request on the jQuery Trac database for this, offering to do the patch and send a pull request if the idea has legs. If you think this is a good idea, your support would be welcome! I'm not saying we have to do it the specific way I've outlined in this post, I'm totally open to other ways to get there. Three lines of code, near-zero overhead, and a familiar paradigm seems pretty good to me, though.
Today
But what if that enhancement doesn't get adopted? Or if we need to do this right now, today, with the current version of jQuery? Do we have to hack the jQuery file, or resort to monkey-patching?
Nope. In the linked Trac ticket, Dave Methvin showed how we can do it today, by adding our own "special" event and watching for the teardown
on it. This uses the event system, but we'll never actually receive the event in the normal way. Here's how it works:
First, we create a "special" event:
$.event.special.ourowndestroy = {
teardown: function() {
// Handle it here, `this` is the element being clean up
console.log(this.id + " being destroyed");
}
};
Then we force that to occur by hooking the event on the element, even though our handler will never get called:
$("selector_for_the_element").on("ourowndestroy", function() {
// This is never called
});
Here it is in action using jQuery 1.7.2.
I've put a function there to make the point that the handler is never called (the action is in the teardown
function); in reality I'd probably use $.noop
or just false
(shorthand for a handler that does return false
) instead.
Now, when an element is being cleaned up, our teardown
function will get called with this
pointing at the element in question. Note that if we didn't hook the event on the element, we wouldn't force the teardown
, so even though our handler isn't called, that's required.
Note: You'll also get the teardown
call if you remove the event handler from the element (and then not when it's cleaned up, as it's not on there anymore), so if you're using this mechanism, either never remove the handler or handle the fact you get the call if you do.
So that's not an ideal way to do it, and it's not the way this stuff is normally done, but it's a passable workaround in the short term — and much better than monkey-patching jQuery's API on the fly.
Happy coding!
Thursday, 2 August 2012
Steve Sanderson's Round-Up of Eight Rich JS Libs/Frameworks
Steve Sanderson's done an interesting round up of the eight libraries and frameworks represented at the Throne of JS conference recently. The conference was about JavaScript applications, not web pages, and focuses on the kinds of projects that help you do your Model-View-Whatever stuff. Worth reading, bookmarking, and re-reading later. Steve declares his interest — he's on the KnockoutJS core team — but keeps it neutral, partially by staying very high-level. Which is exactly what I want from this kind of round-up.
Saturday, 7 July 2012
Well, I'm floored
How do you floor (or truncate) a floating-point number in JavaScript? (E.g., take a value like 5.7 and get just the 5?). The answer is simple: Use Math.floor
. That's the right answer at least 99.99% of the time. It's clear, straightforward, easy to read, easy to maintain. It does what it says on the tin:
console.log(Math.floor(5.7)); // "5"
Sorted.
But you see people doing other things in the name of "performance," which is the purpose of this post: Primarily, to explain what they're doing; and also to see how much actual benefit they're getting from it.
Why performance? On rare occasions, you may have an operation where you need to squeeze every last bit of performance out that you can. The theory here is: Function calls are cheap, but they aren't free, and unless the JavaScript engine you're using does static analysis of your code, when call Math.floor
it has to look up the Math
identifier (which means walking the scope chain to see if it's been shadowed, before ultimately finding it at the outermost level, the global object), look up its floor
property, and then call the function that property points to. So if there's a more direct route, people want to take it when they're looking for every last cycle.
And what they turn to is bitwise operations. JavaScript only has floating-point numbers, of course, but its bitwise operations are defined in terms of 32-bit integers. So when you apply those operations to a number, the first thing that happens is that the number is turned into an integer (whole number) by just chopping off any fractional part (see the internal ToInt32
operation for details). Chopping off the fractional portion is, of course, floors the number — exactly what we want. (Well, with a caveat: The bitwise operators "floor" positive numbers, but they "ceil" negative numbers. "Floor" always goes down, and of course for negative numbers "down" is away from zero rather than toward it; so Math.floor(-12.1)
is -13, not -12. When you just chop off the fractional part like the bitwise ops do, you get -12 instead.)
There are lots of operations to choose from that will floor the number without actually changing its value; I'll list them in rough order of how often I've seen people use them:
- Double bitwise NOT:
~~num
- Bitwise OR with zero:
num | 0
- Left bitwise shift, but not really shifting:
num << 0
- Right bitwise shift, but not really shifting:
num >> 0
- Unsigned right bitwise shift, but not really shifting:
num >>> 0
- Bitwise AND with all-bits-on:
num & 0xFFFFFFFF
- Double bitwise XOR with zero:
num ^ 0 ^ 0
(or indeed, any other number, but zero is easy to type)
But do they really go faster? As always, it depends on what engine you're using:
Figure 1
Math.floor
vs. the bitwise operators
(click image for full-size version)
(interactive version on jsperf)
(Compare only the operations on the same browser; the different browsers were run on different machines, so their speed can't be usefully compared with each other.)
The first take-away from that chart is: Things ain't like they used to be. It used to be that the bitwise operators were a lot faster than Math.floor
. But engines have really stepped up their game in terms of scope chain resolution speed and function call overhead/inlining. (To give you an idea: IE7 does the bitwise OR with 0 nearly nine times faster than Math.floor
, much more dramatic than any of the results above.)
The second take-away is: On most engines, yes, the bitwise operators are faster than Math.floor
, either very slightly faster, or markedly faster. The outlier here is Firefox 3.6, which must have some specific Math.floor
optimization as it screams past the bitwise operators. More recent versions of Firefox don't show that behavior.
The third take-away is: All bitwise operators are not equal. Looking at the chart, the best on most engines is the bitwise OR with zero (num | 0
; the bright red lines) — unless you're using Safari. The most reliable all-rounder (performs well across engines, even if not in first place most of the time) is, oddly, the signed right-shift (num >> 0
; the reddish-pink, second from the bottom of each grouping).
And finally, we can't tell this from that chart per se, but it's worth noting that using the bitwise operators tends to give you the greatest benefit on the slowest engines; e.g., there's not much in it on recent Chrome or Firefox, but there's a much larger difference on the slower IE8, IE9, Opera, and Safari engines (again, Firefox 3.6 seems to be the outlier here).
So if you've been wondering what that n = n|0
was doing in that code you saw, now you know; it's chopping the fractional part off n
— either for performance reasons, or because the coder wanted 12.7 to become 12 and -12.1 to become -12 rather than -13. And it looks like, in those very rare situations where it matters, you do actually get a performance benefit where you need it using the more-obscure, but faster bitwise operation to get the job done. My recommendation: Just be sure to comment what you're doing. :-)
Happy Coding!
Monday, 18 June 2012
9pt grey text on a dark grey background
Is it just me? Am I getting old? (Well, yes, but...) Surely 9pt grey text (#646464) on a dark-grey background (#1C1C1C) qualifies as a Bad IdeaTM? How's this for readable:
Form Factor | mini-PC |
CPU Socket | Intel® Atom™ D525 (dual-core) (1.8 GHz) Intel® HyperThreading™ technology |
Chipset | NM10 Express |
GPU | Intel® GMA 3150 |
Memory | Up to 4GB |
Harddrive | 2.5“ drive bay SATA 3.0 Gb/s compatible |
Graphics Output | 1 VGA / 1 HDMI |
And even that's better than the original linked above, I haven't managed to find all the styles they applied to mess up the text.
Grumble...
Thursday, 14 June 2012
Too Funny - An IE7 Tax
An Australian online retailer has started charging users of IE7 a tax to use the browser on their website. This was inspired, they say, by the amount of time it took their developers to make the site work correctly with IE7 (which 3% of their users were still using). The tax is currently 6.8% — 0.1% per month since IE7 was released.
Presumably they just aren't supporting IE6 at all — if they did, the tax would be a whopping 13% (at the moment).
Cleaning up old Ubuntu kernels from /boot
So what to do? It's quite simple:
- Ensure you don't have a restart pending (Linux can update just about anything without rebooting...except the kernel). If you do, restart.
- Check to see what kernel you're using with uname -a:
$ uname -a Linux forge 3.0.0-21-generic #35-Ubuntu SMP Fri May 25 17:57:41 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux
That's telling me that I'm using kernel 3.0.0-21-generic. - List what kernels you have installed:
$ sudo dpkg -l linux-image-\* | grep ^ii ii linux-image-3.0.0-16-generic 3.0.0-16.29 Linux kernel image for version 3.0.0 on x86/x86_64 ii linux-image-3.0.0-17-generic 3.0.0-17.30 Linux kernel image for version 3.0.0 on x86/x86_64 ii linux-image-3.0.0-19-generic 3.0.0-19.33 Linux kernel image for version 3.0.0 on x86/x86_64 ii linux-image-3.0.0-20-generic 3.0.0-20.34 Linux kernel image for version 3.0.0 on x86/x86_64 ii linux-image-3.0.0-21-generic 3.0.0-21.35 Linux kernel image for version 3.0.0 on x86/x86_64 ii linux-image-generic 3.0.0.21.25 Generic Linux kernel image
- Uninstall the oldest one(s):
$ sudo apt-get purge linux-image-3.0.0-16-generic
...and so on, being sure not to uninstall the one you're using.
Thursday, 24 May 2012
Finally, the normative ECMAScript Spec - in HTML
Tuesday, 17 April 2012
John Cleese on Creativity
Go watch it. Go watch it now. Utterly brilliant.
Wednesday, 4 April 2012
Announcing Lineage
Note: As of late 2015, I don't use Lineage
anymore, there's no need. I use the class
features of ES2015 (aka "ES6") instead. If my target is a browser, for now I transpile with Babel (no need when working in NodeJS, the latest Node uses the latest V8 which has solid support for ES2015).
Just a brief post to announce my latest mini-project, Lineage. It's a small, simple toolkit for creating JavaScript constructor functions and their prototypes ("classes," if you will) in a straight-forward and concise way. From the project home page:
- Lineage's API lets you define prototypes with a very concise syntax, while still encouraging you to create functions with real names (rather than anonymous functions); this helps your tools help you (debuggers show function names in call stacks, for example).
- Lineage provides a highly efficient mechanism for "supercalls" (calling into the parent prototype's versions of methods from an instance using a derived prototype).
- Lineage's API encourages and supports use of the module pattern for each constructor and its prototype.
- Lineage is small, <3k compressed (gzips to <1,500 bytes, a quarter of which is the MIT license) — because it doesn't try to reinvent inheritance, it just simplifies access to the power of JavaScript's prototypical inheritance.
Here's an example of defining a constructor called Thing
with a spiffy
function on the prototype:
var Thing = Lineage.define(function(p) {
p.spiffy = function() {
console.log("I'm a spiffy thing!");
};
});
...or if like me you prefer your functions to have names:
var Thing = Lineage.define("Thing", function(p) {
p.spiffy = Thing_spiffy;
function Thing_spiffy() {
console.log("I'm a spiffy thing!");
}
});
Now, with such a trivial example, that doesn't offer you much on top of the raw equivalent:
var Thing = (function() {
function Thing() {
}
Thing.prototype.spiffy = Thing_spiffy;
function Thing_spiffy() {
console.log("I'm a spiffy thing!");
}
return Thing;
})();
...and that's the point, Lineage works with JavaScript's natural inheritance, it doesn't try to reinvent things. But when you get into inheritance, and in particular start making supercalls, Lineage reduces the code markedly while ensuring everything is hooked up properly, and does so in a way that's easy to use correctly, without retyping a lot of boilerplate code.
Rather than loading up this post with code examples, I'll point you to the progressive series of examples on the Lineage Comparison with Plain JavaScript page for more.
I'm using Lineage in projects now, and so far I'm really liking the simplicity of it. I hope you will too! If you do play with it, please send comments (positive and negative!), the feedback is very welcome.
Happy coding!
Tuesday, 6 March 2012
Adding language choice to FogBugz's code snippets
Surprisingly, the "code snippet" widget used by the FogBugz wiki feature doesn't support telling the pretty-printer (they're using Google's google-code-prettify script) what language the text is in. Since the script can't always tell what language the code is in, this is a problem. And apparently, I'm the first one to ask about this. Wow.
The answer is to write a BugMonkey script and install it in your FogBugz installation. Here's my first take at it, dashed off fairly quickly but apparently functional:
name: Add language support to code snippet pretty-printing in FogBugz
description: Fixes code snipeet pretty-printing in FogBugz by adding the ability to specify a language.
author: T.J. Crowder [tj at crowder software dot com]
version: 1.0.0.0
js:
// Written by T.J. Crowder [tj at crowder software dot com]
// Licensed under the Creative Commons Attribution License 2.0 (UK)
// http://creativecommons.org/licenses/by/2.0/uk/
//
// At the beginning of each code snippet, you can optionally include a line
// defining the language, in the form:
//
// lang_xyz:
//
// This must be the first line.
//
// The script below will find these, extract the "xyz" from it, remove it and
// any line break following it, and add "lang-xyz" to the `pre` element.
// If any matches were found, when done `prettyPrint` is called to reformat
// the elements.
//
// Example:
//
// lang_sql:
// -- A comment
// CREATE TABLE [Foo] (
// [Bar] NVARCHAR(MAX)
// )
//
// ...renders without the first line, with the class "lang-sql" on the element
// so the pretty-printer knows what the language is.
//
// This code may be fairly fragile, depending on the precise workings of the pretty
// printer. It would be better BY FAR if FogBugz updated the code snippet widget to
// support specifying the language.
//
// Many thanks to Ben McCormack and Michel de Ruiter for pointing me in the right
// direction here: http://fogbugz.stackexchange.com/questions/10065
(function($) {
// Our handler
function handlePrettyLanguages() {
var changes = false;
$("pre.prettyprint").each(function() {
var pre, firstElement, span, match, lang, nextpun, nextbr;
firstElement = this.firstChild;
while (firstElement && firstElement.nodeType !== 1) {
firstElement = firstElement.nextSibling;
}
if (firstElement && firstElement.tagName === 'SPAN') {
pre = $(this);
span = $(firstElement);
match = /^\s*lang_([A-Za-z0-9_]+)\s*$/.exec(span.text());
if (match && match[1]) {
lang = match[1];
nextpun = span.next("span.pun");
if (!nextpun[0]) {
nextpun = span;
}
nextbr = nextpun.next("br");
if (!nextbr[0]) {
nextbr = nextpun.next().children().first();
if (nextbr[0] && nextbr[0].tagName !== "BR") {
nextbr = $();
}
}
pre.addClass("lang-" + lang);
span.remove();
if (nextpun !== span) {
nextpun.remove();
}
nextbr.remove();
changes = true;
}
}
});
if (changes) {
prettyPrint();
}
}
// Hook it up on page ready and when BugViewChange events occur
$(handlePrettyLanguages);
$(window).on('BugViewChange', handlePrettyLanguages);
})(jQuery);
You install that via My Settings | Customizations.
Happy pretty printing!
Thursday, 1 March 2012
Match everything...except!
Micro-post:
I was truly shocked to find today that in JavaScript regular expressions, .
(the decimal point) doesn't do what I thought it did. I thought .
meant "match any character." You too? Yeah. But it doesn't. Specifically, .
doesn't match line terminators (so, \r
, \n
, \u2028
, and \u2029
). From Section 15.10.2.8:
The productionAtom :: .
evaluates as follows:
- Let A be the set of all characters except LineTerminator.
- Call CharacterSetMatcher(A, false) and return its
Matcher
result.
...which if you spend really quite a long time looking tells you that .
matches anything but line terminators.
Maybe I'm just parading my ignorance here, but I would have thought that absent the "multiline" flag or something, .
matched everything. Nope. If you want to do that, use [\s\S]
(e.g., everything that either is or isn't whitespace).
Happy coding!
Tuesday, 28 February 2012
Creating a function with a true name defined at runtime
I used to have an article here showing how to dynamically create functions with true names. Except it didn't work properly on Firefox and there's a much better way (which does work properly on Firefox) described in this article by Marcos Cáceres. It looks like this:
var name = "foo";
var func = new Function(
"return function " + name + "(){ alert('sweet!')}"
)();
Yes, the Function
constructor is basically a call to eval
, so you'd only do this with input you control well. But when you need to do it, this is how.
Nice one, Marcos!
Sunday, 26 February 2012
Google Code - Error retrieving directory contents
I dropped by one of my Google Code projects, a trivial little jQuery placeholder
functionality shim called place5, and was quite surprised to see, on the Source tab, the message "Error retrieving directory contents". Now, I have backups (and you do too, of anything you host externally, right?), so I wasn't panicked or anything, but I was still...jarred.
Some searching around revealed that people get this when they've changed their source control system (e.g., from mercurial to git, or subversion to mercurial, etc.). I hadn't changed my source control system, but looking at the Source tab again I saw that it was showing an empty git tree (with the error), and I thought: "Was I using git for this?"
Answer: No, I wasn't. I'd been using subversion. So what the...? So off to Administer, and under Source | Repository Type it said "default" (which appears to [now] be git). Setting it back to subversion corrected the error and restored source browsing.
I mention this for two reasons: Firstly, I figure I won't be the only one, so I thought I'd write this down in case someone runs into the same problem and finds this post. But secondly, it highlights a general principle: It's very useful to have your settings system have the concept of a "default" choice, so if you update defaults, people start seeing the new thing. But when you update a default that's going to break things for people, it's pretty important to change the setting for anyone using "default" to the new, specific choice for the old default. Because breaking things unnecessarily is doubleplus ungood, ya know?
Tuesday, 14 February 2012
Getting rid of "What's Hot"
Google have finally made it possible to get the "What's Hot" rubbish out of your main Google+ stream. Here's how:
- Go to Google+.
- Click "What's Hot" on the left-hand side.
- At the top of the page, there's a subtle little slider (basically an O on a line). Move it all the way to the left.
(If you don't see a slider at the top of your What's Hot page, just wait a day or two for the rollout to come to a server near you.)
That's it, you're done. Yay!
Friday, 10 February 2012
`forEach` and runtime cost
Just a tiny one today, mostly to write this down somewhere:
As you all know, ECMAScript5 adds forEach
to arrays, where you supply a function that gets called for each element in the array. There are lots of benefits to this, not least variable scoping on the index and value variables and a bit less typing, but don't all of those function calls add up to a significant runtime cost?
No, they don't.
I got curious about it (I have a tendency to micro-optimize, which I'm trying to break myself of), so I tested it on the slowest (desktop) browser currently in use: IE6. Specifically, IE6 running in an old Windows 2000 VM I have lying around. I tested the performance of looping through a 100-entry array both with and without calling a function. Without the function call, IE6 looped through the array ~4,500 times in a second (that's 450,000 loop iterations/second). With the function, it managed ~2,000 times a second (200,000 loop iterations/second). So while that's a big relative difference (56% slower!), in real terms it falls into fergedaboudit territory: 2.78 microseconds of overhead. You heard, me, microseconds. That's 0.00278 milliseconds.
Now, I'm not going to say there aren't places where it could matter. I am going to say that they're going to be extraordinarily rare, I'd wager I'll never run into a situation where it makes a difference and nor will you. Whatever else you're doing in the loop body is totally going to wash out the function calls. Really.
Happy coding!