Adventures in Engrish
Jamie Talbot
This user hasn't shared any biographical information
Homepage: http://jamietalbot.com
Posts by Jamie Talbot
Object Oriented jQuery Plugins Mk 2
Aug 26th
In a recent post, I outlined a method to abstract away the complexity of creating an encapsulated jQuery plugin. However, as was pointed out in the comments, there was a missing piece that didn’t allow for arguments to be passed through. More seriously, there was an issue with the binding of the facade function, which meant that only the last defined public function in the class could be called.
As an aside, if you need to bind a variable at the time that it is defined, it isn’t enough to define an anonymous function with a reference to the closure, as that can change by the time the function is called. The bug in my code was in the piece that bound the facade function to the set member functions.
for ( var i in template) {
if (typeof (template[i]) == 'function') {
result[i] = function() {
this.each(function() {
this[i]();
});
};
}
}
By the time the inner function is called, “i” has already been re-bound to the final function name in the template. The solution is to bind the inner function name to the outer function name at the time of definition, which we can do by wrapping it in (yet another!) function.
// Iterates through the set calling the specified function.
function makeIteratorFunction(f, set) {
return function() {
for ( var i = 0; i < set.length; i++) {
set[i][f].apply(set[i][f], arguments);
}
};
}
and then calling that function:
if (template) {
for ( var i in template) {
if (typeof (template[i]) == 'function') {
result[i] = makeIteratorFunction(i, result);
}
}
}
At this point, although “i” will continue to change as the loop continues, the function call is bound through the closure on “f” in the auxiliary function, which remains fixed. Google Chrome’s developer tools certainly make following all that a lot simpler! I’ve updated the plugin with these improvements, which also enables us to pass arguments through, finally allowing:
$('#foo').myplugin().publicMethodWithArguments('hello');
You can get the updated plugin here. Feedback welcomed!
Object Oriented jQuery Plugins
Aug 22nd
I’ve recently begun the process of porting some javascript library code from Prototype to jQuery, and on the whole it hasn’t been too problematic. I really like the element-centric nature of jQuery, whereas Prototype is more like a excellent set of useful static methods. There were only a couple of things I found myself really missing, and they were enumerables, and elegant plugin encapsulation. The first problem was solved with Xavier Shay’s nice enumerables plugin. The second one was more of a challenge.
The lack of encapsulation for jQuery plugins seems to be a common frustration, and there are lots of queries on the web along the lines of “how do I add public methods to a jQuery plugin”. The best solution I found came from Hector Virgen, which allows you to do something like this:
var pluginInstance = $('#foo').data('myplugin');
pluginInstance.publicMethod();
That’s pretty neat, but I didn’t really like the idea of having to go through the data object each time. A couple of other people in the comments felt the same way, but there didn’t seem to be any solutions forthcoming, so I had a crack. What follows is largely based on Hector’s code, so you should go and read that first before you go through this.
We start off with a basic plugin shell, slightly modified from Hector’s, per my taste:
(function($) {
var Celsus = Celsus || {};
Celsus.MyPlugin = function(element, options) {
// Private members
var elem = $(element);
var settings = $.extend({}, options || {});
// Private methods
function _privateMethod() {
console.log("This is a private method!");
}
return {
publicMethod: function() {
console.log(elem);
_privateMethod();
return true;
}
};
};
$.fn.myplugin = function(options) {
return this.each(function() {
var element = $(this);
if (element.data('myplugin')) {
return;
}
var myplugin = new Celsus.MyPlugin(this, options);
// Store the new plugin definition in a data object.
element.data('myplugin', myplugin);
});
};
})(jQuery);
This is a pretty good start. However, as Hector points out, the main issue is that the plugin returns a jQuery object to enable chaining. In many complex instances, chaining isn’t necessarily something you’re going to want to do, so we make a small sacrifice and forego that convenience. Instead, we are going to return a set of plugin instance objects:
$.fn.myplugin = function(options) {
var result = [];
this.each(function() {
var element = $(this);
if (!element.data('myplugin')) {
// Initialise
var myplugin = new Celsus.MyPlugin(this, options);
// Store the new functions in a validation data object.
element.data('myplugin', myplugin);
}
result.push(element.data('myplugin'));
});
};
At this point, it’s not looking too great. We’ve broken chaining because we no longer return a jQuery object, but if you try and call
$('#foo').myplugin().publicMethod();
it still doesn’t work. This is because, although each plugin instance has the publicMethod() function, they are contained inside a bare array. At this point we could actually do:
($('#foo').myplugin()[0]).publicMethod();
($('#foo').myplugin()[1]).publicMethod();
Or something similar with each(), but this is very messy. We need a bit of syntactic sugar. To achieve this, the next step is to take that array, turn it into something we can work with, and add a facade, so that every public function we’ve just mixed in is presented as an option on the plugin instance set. We do that by adding the following to the plugin definition:
result = $(result);
var template = result[0];
if (template) {
for ( var i in template) {
if (typeof (template[i]) == 'function') {
result[i] = function() {
this.each(function() {
this[i]();
});
};
}
}
}
Firstly, we convert the array to a jQuery object. Then, we look at the first instance in the set and use that as a template. It should contain all the public functions we’ve defined in our definition class, and all the instances are of the same type, so we can safely use the first entry’s template for all of them. We then enumerate through all the public functions and create a proxy or facade function on the set, which simply calls the closure of that function for each element in the set. This ensures that when you call
$('#foo').myplugin().publicMethod();
it is functionally equivalent to:
$('#foo').myplugin().each(function(instance) {
instance.publicMethod();
});
So that’s pretty cool. We’ve avoided namespace pollution, we can mix in any number of public methods, and private members and methods behave as you’d expect them to. It isn’t possible to access public variables in this manner of course, but that is easily remedied by using public getters and setters. We can even add in a reference back to the jQuery object, so we can get chaining back in in some form:
result.$ = this;
Which lets us do:
$('#foo').myplugin().$.addClass('bar');
This is useful when you’re doing plugin initialisation, but thereafter it’s a bit redundant as the actual plugin call simply returns an object which you then ignore. The only final point is that there’s quite a lot of boilerplate going on here just to get set up. In actual fact, the actions are pretty generic, so we can extract all that code and put it in its own plugin. A plugin to generate a plugin!
(function($) {
$.fn.encapsulatedPlugin = function(plugin, definition, objects, options) {
var result = [];
objects.each(function() {
var element = $(this);
if (!element.data(plugin)) {
// Initialise
var instance = new definition(this, options);
// Store the new functions in a validation data object.
element.data(plugin, instance);
}
result.push(element.data(plugin));
});
// We now have a set of plugin instances.
result = $(result);
// Take the public functions from the definition and make them available across the set.
var template = result[0];
if (template) {
for ( var i in template) {
if (typeof (template[i]) == 'function') {
result[i] = function() {
this.each(function() {
this[i]();
});
};
}
}
}
// Finally mix-in a convenient reference back to the objects, to allow for chaining.
result.$ = objects;
return result;
};
})(jQuery);
With this little plugin, our plugin initialisation code is a lot lighter:
$.fn.myplugin = function(options) {
return $.fn.encapsulatedPlugin('myplugin', Celsus.MyPlugin, this, options);
};
Not too bad! The actual code that specialises a plugin is tucked away in a neatly encapsulated object, we have access to all the public methods defined on it and multiple instances can happily live side by side and be invoked separately without trampling on each other. You can grab a copy of the plugin generating plugin from here. This is still new cod and there might be the odd glitch, so if you spot any, or have other ideas, be sure to leave a comment!
Subtle Behaviour of The Static Keyword in PHP 5.3
Aug 11th
Version 5.3 of PHP added a new, very useful and long-overdue feature allowing for late-static binding using the ‘static’ keyword instead of the ‘self’ keyword. The PHP manual has a good explanation of the difference. However, there is a subtle behaviour that I certainly hadn’t anticipated and might catch you out.
A typical use-case of the new syntax is to lazy-load static variables in inherited child classes, which offers you the choice of avoiding the overhead of object-instantiation to provide class differentiation. Unfortunately, it is not quite as straightforward as you might think. Consider the following piece of code:
class BaseClass {
static $_value = null;
public static function getValue() {
if (null === static::$_value) {
static::$_value = get_called_class();
}
return static::$_value;
}
}
class ChildAClass extends BaseClass {}
echo BaseClass::getValue() . "\n";
echo ChildAClass::getValue() . "\n";
What’s going on here then? When I look at that piece of code, I expect the output to be:
BaseClass ChildAClass
Instead, it appears the call to ChildAClass::getValue() fails the conditional test and returns the static value of BaseClass, giving the following output:
BaseClass BaseClass
Not very helpful. How can we work around this? The answer is to ensure you declare the static variable in each of your child classes as well as the parent. It’s straightforward enough, but a pain to remember every time. The following example demonstrates:
class ChildBClass extends BaseClass {
static $_value = null;
}
echo BaseClass::getValue() . "\n";
echo ChildBClass::getValue() . "\n";
BaseClass ChildBClass
So it appears (at least for PHP 5.3.3 (OS X)), that static only really means static if you declare it yourself each time. This might be expected behaviour, but I consider it a bug, and it can certainly lead to hard to debug situations. It doesn’t seem to be documented clearly in any standard location that I could find.
Short story – if you are looking to lazily-populate static variables using the new syntax, be sure to declare the variables in all of the child classes you are going to use!
Do You Still Want Gengo?
Jun 30th
Gengo was (and remains) a project that I am very fond of. Originally developed for my own personal use to blog in Japanese as well as English, it turned into a fairly full-featured plugin that was used by quite a few people. Unfortunately, time pressures meant that I had to drop support for it a few years ago. Even so, every few weeks I get an email or comment (usually nothing to do with the post it was written against!) asking me to consider restarting development.
It might just be the alcohol talking, or end-of-financial-year madness, but with WordPress 3.0 recently out and a couple of requests already this week, I’m seriously considering starting development again. I do have a couple of projects I want to do though, so I only want to dedicate time to Gengo if it’s going to be used. My Japanese has sadly diminished to the point where I’m practically mono-lingual again, so I’m not going to be blogging in multiple languages any time soon, and it would purely be for others to use. So, if enough people email me or comment in the next week or so, I’ll give it a crack. Second time around, I’ll hopefully be able to design it more cleanly and more quickly, and WordPress’ plugin architecture hopefully hasn’t changed too much while I’ve been away.
So if you want to see a new version of Gengo, please let me know. On the other hand, I hear very good things about WPML, so If Gengo’s time has passed, feel free to say that too! I won’t have hurt feelings, promise
Fabulous Capitulation
Jun 27th
And so England bow out of a major competition yet again with a whimper, not a roar, and a defeat so ignominious that it erases all of the good will generated during the impressive qualifying campaign. Yet again, England flattered to deceive, and yet again, the English supporters fell for it. While they were hardly stellar in the run-up to the competition, they did at least possess that hard-to-beat quality, the “winning ugly” ability which is an absolute necessity at this level. Not so tonight. Tonight, the mask slipped and they were just plain ugly, put to shame by a youthful and inexperienced German team who schooled them in every area, in every position.
The disallowed goal before half-time will surely be over-analysed by the talking heads in the coming weeks, and ruminated on in the pub for years to come. The truth is, even had the goal stood, the result probably wouldn’t have changed, and would have merely put a plaster on a compound fracture. Had England limped on, they would have surely been embarrassed by the next team. Better that they be put out of their misery early.
The litany of mistakes in this tournament is too long to list, but there were notable low-lights. Tactically speaking, in the first game, fielding half-fit players and a goalkeeper with a history of mental weakness portended the tenor of the games to come. There was no tempo, no urgency, from any of the players. The “defending” of Germany’s first goal would have been considered poor on the schoolyard. Steven Gerrard’s captaincy was remarkably insipid, and a far cry from what he does for Liverpool. Captain Fantastic, he was not. It’s virtually impossible to write about Wayne Rooney’s contribution, because that would imply that he’d played in the tournament, and I’m not entirely convinced that he did.
It is surely one of the most puzzling mysteries in football; how a team of undoubtedly world-class players, the vast majority of whom regularly play in the fastest and most intense club competition in the world, can come to a tournament such as this and play with less intensity than New Zealand. The disinterested nature of the players, jogging around the field, waving a foot here and there, and pouting when decisions didn’t go their way, was frankly embarrassing. There was a smell of entitlement about each performance, as though the players were surprised that the opposition didn’t just hand them the win. “Don’t you know who we are? Just lie down will you, there’s a good boy”. As it turns out, the only team to capitulate was Capello’s.
Now is not the time for solutions. Now is the time for anger. Cleansing, righteous anger at a team who have let down their country, not because they didn’t win, but because they didn’t even compete. England has a proud footballing history, littered with glorious and noble defeats, and even the odd spellbinding win. To go out in such a tepid fashion should be considered beneath us.
The only positive you could draw is that with England out, the average quality of the remaining teams has gone up. The competition has lost a squad of 23 anonymous millionaires, and is richer for it.
Why You Probably Support Electoral Reform
May 19th
It’s been heartening to see a sizeable and noisy push towards meaningful political reform in England. While the coalition has made a number promises on changes to the Lords, to constituency sizes and electoral reform, including a referendum on the alternative vote, there is still sizeable resistance in the Commons on both sides of the aisle, particularly to the latter policy. We need to continue to put pressure on our elected representatives to follow through with at least that much.
There are many misconceptions about the the concepts of electoral reform, proportional representation and the alternative vote and a number of arguments are regularly raised in opposition to any proposed changes. A sample of those arguments follow. This is something of a straw man piece, but the statements rebutted below are absolutely representative of what is being written in more conservative articles and blogs around the UK that support the existing system and are resistant to change.
This piece isn’t targeted at everyone in the UK; only those who don’t live in marginal constituencies and whose vote doesn’t really matter because they live in a “safe” constituency. So only 95% of us then. Hell, even the Eurovision Song Contest is more proportional than British elections. Imagine if each member state only had one vote in that competition. We’d be on nul points for eternity (deserving or not).
First past the post works, it’s easy to understand and we don’t need to change it
First past the post (FPTP) is absolutely a legitimate method of polling people, but it is far better suited to competitions where there can be a single winner, like presidential elections. For large populations, it can lead to peverse results where the loser in terms of the popular vote still commands a majority in the House of Commons. Being easy to understand is an admirable goal, but having an elected member who is representative of the majority of his or her constituency is far more desirable. The majority of seats are currently won with a plurality of votes. Politicians could claim a much better mandate if they had more than 50% of their local vote.
If you prefer the idea of your vote counting, rather than clearly understanding that your vote won’t count, you support electoral reform!
If you don’t live in a marginal constituency, politicians don’t bother to seriously campaign in your district and you wonder what the point of voting is because “Labour / Conservatives / Lib Dems always get into power”, you support electoral reform!
Gordon Brown was an unelected Prime Minister, and his successor would have been an unelected Prime Minister
As stated even by David Cameron himself, we have a parliamentary system in the UK, not a presidential one. We do not vote for Prime Ministers, we vote for local representative MPs. Those MPs choose the party leader, and they can choose him or her at any time. The leader of the party who can command the confidence of the House of Commons by having a majority of seats is the Prime Minister. If you don’t like this, you support electoral reform!
A government made up of the second and third place losers would have been an illegitimate “Coalition of Losers”
Any party that can command a majority in the House of Commons is by definition a legitimate government. For completeness (though it doesn’t actually make any difference under the FPTP system), Labour and Liberal Democrats together polled 53% of the national popular vote. If you think that the party that comes first in the popular vote has the right (not just the chance) to form a government, you support electoral reform!
Only 23% of people voted for Liberal Democrats, therefore people don’t care about Proportional Representation, so Nick Clegg should have just joined the Tories immediately
Leaving aside for the moment that it was just smart negotiating, the perceived collapse of the Lib Dem vote doesn’t imply that people don’t care about PR. (And I say perceived because they actually increased their share of the vote.) It could conceivably imply that 77% of people disagreed with the entire Lib Dem manifesto, but the truth is likely to be a little more nuanced. Using the same flawed logic, you could argue that 64% of people were specifically against inheritance tax cuts.
The current electoral system encourages people to vote deliberately against the party they like the least to guarantee they don’t get into power. This tactical voting significantly harms minority parties including the Liberal Democrats. It is likely that a significantly higher percentage of people would vote Lib Dem if they thought they could actually achieve power. A Lib Dem vote has long been synonymous with “a wasted vote”. In recent polls, a significant percentage of people have been in favour of PR (62%) compared to those against (13%). They might not consider it the most important issue, but they still want reform.
If you think that achieving 36% of the popular vote, for 13% of the available seats (as all but the main parties achieved) is undemocratic, then you support electoral reform!
Proportional Representation leads to hung parliaments
The response to this can be summarised in three parts: not necessarily; so does FPTP, and; so what? Australia has the alternative vote system for its House of Representatives, which is more proportionate that FPTP and it currently has a majority Labour government. The second and third largest parties, the Liberals and the Nationals are in a coalition in opposition. Given the recent results, nobody can now argue that FPTP doesn’t also lead to hung parliaments. And who’s to say hung parliaments are bad anyway? Germany is the strongest economy in Europe and has had coalition governments for decades. The negotiations between the Liberal Democrats and the Tories has blunted the edge of what might have been a supremely austere conservative backlash. While nobody is perfectly happy with the outcome, you could perhaps make the argument that everyone is less unhappy than they might have been. Right-wing conservatives might well be upset about the inheritance tax cuts vanishing, but it’s a much better outcome for them than not being in government. Progressive voters aren’t going to be too keen on the cuts that are coming, but the concessions that the Lib Dems extracted are much more palatable than a minority Conservative government.
If you believe that government should represent the wishes of all the people, and not just people like yourself (and admittedly, this is the hardest one to sell), and if you believe that compromise is a necessary and honourable part of life, you support electoral reform!
And if you do support it, let your local MP know about it.
Using Multiple Start and End Keys for CouchDB Views
Mar 24th
CouchDB view collation is great and only has one real drawback that has caused me any real pain – the inability to handle queries that need to be parameterised by more than one dimension. These are suprisingly common, including problems such as “find me posts in Category A in March”.
This can be handled with a function that emits keys like:
["Category A", "2010", "03", "Post 1"] ["Category B", "2010", "03", "Post 2"] ["Category A", "2010", "03", "Post 3"]
and then use:
startkey=["Category A","2010","03"]&endkey=["Category A","2010", "03",{}]
However find its reciprocal “All March posts regardless of category” is problematic. You can’t do:
startkey=[*,"2010", "03"]&endkey=[*,"2010", "03",{}]
where * (or _, or nil, or pass) would represent “all”.
To handle this, there are currently only 2 options; design a new view with the the key components ordered differently, such that they emit:
["2010", "03", "Post 1"] ["2010", "03", "Post 2"] ["2010", "03", "Post 3"]
or, make multiple connections to the database like
startkey=["Category A","2010","03"]&endkey=["Category A","2010", "03",{}]
startkey=["Category B","2010","03"]&endkey=["Category B","2010", "03",{}]
startkey=["Category C","2010","03"]&endkey=["Category C","2010", "03",{}]
where you have a query for each category.
Neither approach is particularly satisfactory. On a recent particular problem set, a single view would be many hundreds of gigabytes of data, and while space is cheap, it’s not that cheap. Additional views were not an option. That same data set contained around 2000 different categories (or their equivalent) and 2000 connections for a particular query seemed excessive.
Since 0.9, Couch has had a way of passing multiple keys to a query in the post body of a view request. Unfortunately, this only supported precise keys, not start-end key ranges. There has been a ticket in the issue tracker to add this additional support since October, but it’s classed as a minor priority and nothing had been done on it. So I decided to have a crack.
On the face of it, it seems like a fairly simple change, only affecting the HTTP View Erlang module. On the other hand, I’ve probably written about 100 lines of Erlang in my life and never looked at the CouchDB code before, so it’s entirely possible I’ve done something wrong. Regardless, the following is a simple solution that appears to work correctly.
The output_map_view and output_reduce_view functions already had the ability to handle start and end keys, but they were being artificially restricted to treat the supplied keys and both start and end. I used Erlang’s pattern matching to make this a little richer:
case Key of
{[{<<"startkey">>,StartKey},{<<"endkey">>,EndKey}]} ->
nil;
_ ->
StartKey = Key,
EndKey = Key
end
and then passing those new variables in the appropriate place. This seemed to work well. I presume that the Keys parameter is processed just like multiple connections, and then the results aggregated, because the results are exactly the same as a call with the same parameters in the query string.
One final change was that group_level=X is mysteriously disallowed for Multikey queries. I took a punt and removed this restriction and it all seemed to work fine. I can only guess that this restriction didn’t make sense when you had to pass precise keys.
I then query using the following as POST data:
{
"keys": [
{
"startkey": ["Category A","2010","03"],
"endkey": ["Category A","2010","03",{}]
},
{
"startkey": ["Category B","2010","03"],
"endkey": ["Category B","2010","03",{}]
}
]
}
With this solution, I’m able to query 2000 services simultaneously, group them at any level I like, and get back the results at the lightning speed I’ve become accustomed to.
One small caveat: If I want to get back keys across non-contiguous blocks like this:
startkey=["Category A","2010","03"]&endkey=["Category A","2010", "03",{}]
startkey=["Category A","2010","06"]&endkey=["Category A","2010", "06",{}]
startkey=["Category B","2010","03"]&endkey=["Category B","2010", "03",{}]
startkey=["Category B","2010","06"]&endkey=["Category B","2010", "06",{}]
To get all posts in Category A and B in March and June, I can. However, if I have a reduce function and group at level 1, I still end up with 4 rows, 2 for Category A, 2 for Category B. I think this is because the queries are being run independently, without reference to the other. To do a full aggregation across time periods (for example to get the total number of posts by category in March and June), I’d still need to do a client aggregation on the resulting data-set. This may or may not be a big problem for you; it’s certainly something I can live with.
The CouchDB issue lives here, and the patch to 0.10.1 lives here.
Handling JSON Objects in CouchDB Native Erlang Views
Mar 18th
I’ve been working with CouchDB a fair bit in recent weeks and am really enjoying it so far. Once I got my head around how to structure views and take advantage of view collation, I found it to be far more expressive than I first thought.
I still have a couple of gripes, the largest one of which is that you can’t use a wildcard parameter at the beginning of your view keys, so if you need to get “items by user by category” and “items by category by user”, you need two views. I’m sure there are good architectural reasons for this, but for me it’s the one place where collation lets me down. For at least one of the solutions I’m working on, multiple views are a major problem, as even one takes up 120GB (and counting).
But, to the main point. Native Erlang views are now possible, and if you can create them, potentially significantly faster than Javascript ones. There are a couple of gotchas though, not least for me the handling of JSON objects.
We start with a document like this:
{
"_id": "36kem",
"_rev": "1-c895d5a55945a9898880bf870a3b3025",
"type": "usage",
"timestamp": [
"2010",
"02",
"28",
"23",
"10"
],
"data": [
{
"t": "E000005861",
"i": "232920",
"o": "2365730"
},
{
"t": "E000006504",
"i": "15784",
"o": "17786"
},
{
"t": "E000006505",
"i": "16661",
"o": "17786"
}
]
}
In reality there are thousands of entries in the data array, but this will do. Our aim is to emit one key-value pair for each item in the “data” field of each document of type “usage”. In Javascript this is pretty trivial. Erlang however, proves more of a challenge.
Based on pointers from the CouchDB Wiki, I started with:
fun ({Doc}) ->
case proplists:get_value(<<"type">>, Doc) of
<<"usage">> ->
Emit(proplists:get_value(<<"_id">>, Doc), null);
_ ->
ok
end
end.
and was very happy to see that work. Two things to note here: Don’t forget the {} around the Doc in the function definition or you’ll get strange errors, and; to get the value of a field in a document, you can use the standard proplists:get_value(<<"fieldname">>, Doc) construct. So far so good.
The main issue for me came with manipulating the “data” field. I didn’t actually want to emit null, but instead the “i” and “o” parts of the data field. First off, I tried:
lists:foreach(fun(Item) -> Emit(null, [proplists:get_value(<<"i">>, Item), proplists:get_value(<<"o">>, Item)]) end, proplists:get_value(<<"data">>, Doc)
But met with some (very long) errors. (Gripe number two – they could really do with humanising the Erlang crash dump.)
It took me quite a few attempts, including stripping it right back to confirm that I had an array to iterate and that each object does in fact contain an “i” and an “o” field, before I found the problem, which is this:
Even though Documents are defined within {} braces, and JSON objects within that definition are also defined within {} braces, you cannot access them the same way in an Erlang view.
proplists:get_value(<<"field">>, Doc) is fine for the document as a whole, but you can’t access JSON objects the same way. Bad assumption on my part. Luckily, the answer I got to another Stack Overflow question recently pointed the way.
To access the data we need to pattern match the components using the Erlang representation of a JSON object, like so:
{[{<<"t">>, TrackingID},{<<"i">>, In},{<<"o">>, Out}]} = Row
Ugly, hey?
Useful though, as it extracts the TrackingID, In and Out values all in one go, kind of like a list() statement on steroids.
With that in place, and a little more tidying up of the code, we arrive at:
fun({Doc}) ->
case proplists:get_value(<<"type">>, Doc) of
<<"usage">> ->
[Year, Month, Day, Hour, Minute | _] = proplists:get_value(<<"timestamp">>, Doc),
lists:foreach(fun(Row) ->
{[{<<"t">>, TrackingID},{<<"i">>, In},{<<"o">>, Out}]} = Row,
Emit([TrackingID, Year, Month, Day, Hour, Minute],[In, Out])
end, proplists:get_value(<<"data">>, Doc));
_ ->
ok
end
end.
That little beauty lets me query the usage of a service at any granularity over data from the last 7 years in a faster time than the browser can render it. Across an HTTP connection to a data source 1000km away. On development hardware.
CSS Technique: Morning Sunset
Mar 10th
After coming across an excellent article on generating full page images, I had the idea that it would be cool to blend between multiple images as a user scrolled down the page. The somewhat artistic conceit that a user could scroll a similar scene from morning to sunset, ironically came to me at sunset on Saturday and was finished by morning!
The effect is pretty simple to set up, though does require a specific bit of markup. We start with 2 images and set a z-index on them, such that the first one is in front of the second. With the full page image CSS rules, the first image fills the screen and the second is completely obscured.
<img id="morning" class="bg" style="z-index: 2;" src="morning.jpg" /> <img id="sunset" class="bg" style="z-index: 1;" src="sunset.jpg" /
For the CSS, In addition to the standard full page image rules, I add an additional higher z-index, plus a little bit of transparency This allows the content to sit on top of both of these images, and for the effect to be more pronounced.
div#content {
/* This is the only important rule */
/* We need our content to show up on top of the background */
position: relative;
z-index: 10;
/* Added some opacity to demonstrate the effect better */
opacity: 0.8;
filter: alpha(opacity=80);
}
So far, so what? We’ve arranged for a user to download an image he can’t see – not so good. The magic comes with a blending function tied to the scrollbar. The idea is that the top layer becomes more and more transparent as the user scrolls through the content.
In working with the Zend Framework, I’ve been getting to grips with Dojo and its supporting classes, so I was happy to see that Dijit had tools for getting the dimensions of the viewport. With this information, I was able to calculate the scroll ratio, which gave me a number ranging from 0 at the top of the page to 1 at the bottom.
Dojo also has a great style() function, which allows you to set opacity and have it “just work”, across all browsers, regardless of their non-standard filter() shennanigans. At the outset, the top layer image has an opacity of 1. Subtracting the scroll ratio from this allows it to be fully opaque at the top of the page, and fully transparent at the bottom.
dojo.subscribe("/window/scrolled", function(e){
// Calculate the scroll percentage, and adjust the opacity of the top layer, appropriately.
var vp = dijit.getViewport();
dojo.style("morning", {
"opacity": 1 - (vp.t / (document.documentElement.scrollHeight - vp.h))
});
});
There is some rate-limiting code going on to prevent the event firing continuously and slowing down the page. That came from a helpful Dojo Cookie by Peter Higgins over at Dojo Campus. I haven’t played fully with the rate limiting yet, but 50ms seemed to give a reasonable balance of subtle movement without overloading the page.
Degradation is variable – without Javascript, the user just sees the top image and there’s some overhead of the second image that is never seen. Without CSS, there’s more of a problem, as the images are inlined in the page, which pushes all the content down. If there is a full page image solution using background images only, I’d love to hear about it.
There’s a working, self-describing example of the effect so you can try it out for yourself. It works best in Chrome, with its superior Javascript handling, but works in all modern browsers to a reasonable degree.
The next step is to generalise the code, so that I can pass it an array of image URLs and have it automatically build the markup necessary to generate the effect. With more work on the blending function, I’ll be able to have it blend between multiple layers and potentially follow different rates – I might investigate Dojo curves for that.
I’m not aware of this technique being described anywhere else, but if there are other approaches to doing this, I’d be interested to see them.
Modelling Recurring Events in PHP
Feb 7th
In a previous article, I described how set operations could be modelled in PHP. With that foundation, we can begin to generate complex date criteria suitable for modelling recurring events.
There are a number of different kinds of date condition, which Martin Fowler terms “Temporal Expressions”. Typical temporal expressions include “Last Day in the Month”, “Nth Day of the Week” and “Repeats Yearly”. We can model each of these as a separate class and then combine them as necessary to provide a flexible architecture.
In order to take advantage of the set operations we defined previously, all of the classes must implement the same trivial interface:
interface Celsus_Temporal_Expression_Interface {
/**
* Determines whether the date specified is included in this temporal expression.
*
* @param string $date
*/
public function includes($date);
}
For our first example, let’s model conditions like “11th day of the month”. By using negative numbers, we can also use the same class to model “11th day from the end of the month”:
/**
* Handles scheduling rules like "11th day of the month".
*/
class Celsus_Temporal_Expression_DayOfMonth implements Celsus_Temporal_Expression_Interface {
/**
* The day of the month we are interested in. If the day is less than zero,
* it is interpreted as being from the end of the month.
*
* @var int
*/
private $_day;
public function __construct($day) {
$this->_day = $day;
}
public function includes($date) {
return $this->_day > 0 ? $this->_fromStartOfMonth($date) : $this->_fromEndOfMonth($date);
}
private function _fromStartOfMonth($date) {
return $this->_day == date('j', strtotime($date));
}
private function _fromEndOfMonth($date) {
$timestamp = strtotime($date);
return ((date('t', $timestamp) - date('j', $timestamp)) + 1) == abs($this->_day);
}
}
Usage is straightforward:
$tenth_of_the_month = new Celsus_Temporal_Expression_DayOfMonth(10);
var_dump($tenth_of_the_month->includes('2010-01-10')); // True
var_dump($tenth_of_the_month->includes('2010-01-07')); // False
$three_days_before_end_of_the_month = new Celsus_Temporal_Expression_DayOfMonth(-3);
var_dump($three_days_before_end_of_the_month->includes('2010-01-10')); // False
var_dump($three_days_before_end_of_the_month->includes('2010-01-28')); // True
A second type of query is of the form “every 3 months”. This is slightly more involved as it needs to also use a specified date as the base from which to start counting:
/**
* Handles scheduling rules like "every 3 months"
*/
class Celsus_Temporal_Expression_MonthsFromStart implements Celsus_Temporal_Expression_Interface {
/**
* The count specifying the interval of months we are interested in.
*
* @var int
*/
private $_count;
/**
* The start date of the sequence. The number is stored in ISO
* format, i.e 2000-12-31.
*
* @var string
*/
private $_start;
public function __construct($start, $count) {
$this->_start = $start;
$this->_count = $count;
}
public function includes($date) {
// Take the specified month, minus the start month, mod the interval. If it is
// zero then this date should be included.
return (0 == ((date('n', strtotime($date)) - date('n', strtotime($this->_start))) % $this->_count));
}
}
Again, usage is similar:
$every_two_months = new Celsus_Temporal_Expression_MonthsFromStart('2010-01-01', 2);
var_dump($every_two_months->includes('2010-03-01')); // True
var_dump($every_two_months->includes('2010-04-01')); // False
Now, making use of our set operations previously defined, we can combine them for more complex rules such as “the last day of every quarter”:
$last_day_of_month = new Celsus_Temporal_Expression_DayOfMonth(-1);
$every_three_months = new Celsus_Temporal_Expression_MonthsFromStart('2010-01-01', 3);
$last_day_of_quarter = new Celsus_Set_Operation_Intersection('Celsus_Temporal_Expression_Interface');
$last_day_of_quarter->addElements(array($every_three_months, $last_day_of_month));
var_dump($last_day_of_quarter->includes('2010-01-31')); // False;
var_dump($last_day_of_quarter->includes('2010-06-30')); // True;
In general, intersections are going to be the most useful set operation for this kind of use, but are not the only possibility. If we modify this to use a Union, we can test to see if dates are either the last day of the month, or within a month every 3 months from the start:
$last_day_of_month = new Celsus_Temporal_Expression_DayOfMonth(-1);
$every_three_months = new Celsus_Temporal_Expression_MonthsFromStart('2010-01-01', 3);
$last_of_month_or_every_three_months = new Celsus_Set_Operation_Union('Celsus_Temporal_Expression_Interface');
$last_day_of_quarter->addElements(array($every_three_months, $last_day_of_month));
var_dump($last_of_month_or_every_three_months->includes('2010-02-28')); // True;
var_dump($last_of_month_or_every_three_months->includes('2010-06-05')); // True;
A handful of temporal expressions can be downloaded here. Further ones are left as an exercise.
With an appropriate database schema for persistence of rules, such as Apple’s iCal reference, this provides a comprehensive method for defining complex date ranges and testing them quickly.