Using OLPC XO as an ebook reader for O'Reilly's Safari Books Online

A year ago I received an OLPC XO (the “$100 laptop”) through their Give One Get One program. I played with it for a few days and found it essentially useless due to unstable and slow software (and lack of WPA support), so it quickly began gathering dust on a shelf (it has since improved).

Last week I was thinking about how cool it would be if Amazon’s Kindle supported O’Reilly’s Safari Books Online service, and I decided to dust off the XO to see if it could be used as an ebook reader for Safari Books. With a little help, it can.

In ebook mode you can scroll in all four directions, page up/down, and jump to the top or bottom of a page, but you cannot click the next/previous buttons within Safari Books. However, GreaseMonkey and a simple userscript can solve that.

The first step is to install the Firefox “Activity”, or a version of Linux that runs a stock Firefox. Then install GreaseMonkey. Finally, install this userscript:

http://tlrobinson.net/userscripts/xo-safari.user.js

This simple userscript intercepts page up and page down (the “O” and “X” game pad) buttons and maps them to “previous” and “next” actions in Safari Books, allowing you to easily switch pages in ebook mode.

A Better BugMeNot Bookmarklet

BugMeNot is a great little service for bypassing the registration process for websites that really shouldn’t require it (ahem, nytimes.com). The bookmarklet brings up BugMeNot for the current website you’re viewing, and gives you login/password pairs which you can then copy and paste.

But wouldn’t it be better if it automagically filled in the username and password for you? I thought so, so I wrote a few lines of code in the form of a bookmarklet and a JSONP web service to do this.

BugMeNot doesn’t provide an API so I had to do a little screen scraping with Hpricot. They also try to obfuscate the usernames and passwords by shifting the characters by some offset calculated from a “key” then Base64 encoding the string, and prepending 4 characters. Luckily their obfuscation was no match for a single line of Ruby:

def bmn_decode(input, offset)
  # decode base64, strip first 4 chars, convert chars to ints, substract offset, convert back ints back to chars
  input.unpack("m*")[0][4..-1].unpack("C*").map{|c| c – offset }.pack("C*")
end

The bookmarklet makes the request via an injected <script> tag. When it’s callback gets called it finds the most likely input elements for the username and password and fills them in with the result.

The Rails app consists of a single action that makes a request to bugmenot.com for the specified site, extracts and decodes the usernames and passwords, and picks the one with the highest rating. It then returns the result as JSON wrapped in a function callback (i.e. JSONP)

I’m not going to post the location of the live JSONP web service since BugMeNot limits the number of requests you can make, but the code is available on GitHub.

Automagically Wrapping JavaScript Callback Functions

One very nice thing about JavaScript is it’s support for first-class functions and closures. Crockford calls JavaScript “Lisp in C’s Clothing”. I’m no Lisper, but I enjoy I discovering new tricks or applications of functional programming in JavaScript.

I wanted to hook all the browser’s asynchronous JavaScript “entry points” : events, timers, asynchronous XMLHttpRequests, script tags, and “javascript:” URLs. This article deals with the first two, events and timers.

To do this, I figured I could somehow “wrap” all the callback functions passed to setTimeout(), setInterval(), and addEventListener(). By “wrapped” I mean another function that we specify calls the original function, rather than the original function getting called directly. This allows us do whatever we want right before and after calling the original function, including manipulating the arguments and return value, logging to the console, calling other functions, putting it in a try/catch, etc.

Here’s the implementation of “callbackWrap”, the function that does all the work:

function callbackWrap(object, property, argumentIndex, wrapperFactory, extra) {
    var original = object[property];
    object[property] = function() {
        arguments[argumentIndex] = wrapperFactory(arguments[argumentIndex], extra);
        return original.apply(this, arguments);
    }
    return original;
}

To use it, you need function that takes another function as a parameter and returns a wrapped version of that function which does whatever you want it to. In this case it just prints out “whoooaaaaa:” followed by the “extra” parameter:

function logWrapper(func, extra) {
    return function() {
        console.log("whoooaaaaa: " + extra);
        return func.apply(this, arguments);
    }
}

Finally, to actually use this, we call callbackWrap with the object that contains the function we want to wrap, the name of the function property, the index of the callback argument to the function (0 for setTimeout/setInterval, 1 for addEventListener), a wrapper “factory” function, and optionally an extra argument that’s made available (via the closure) to the wrapped function. The extra parameter can be used for any data you need to pass to the wrapper function, or it can be ignored.

Here’s how this would be used on setTimeout, setInterval, and addEventListener on window, Element.prototype and Document.prototype (so it applies to all Elements and Documents):

callbackWrap(window, "setTimeout", 0, logWrapper, "wrapped a window.setTimeout!");
callbackWrap(window, "setInterval", 0, logWrapper, "wrapped a window.setInterval!");
callbackWrap(window, "addEventListener", 1, logWrapper, "wrapped a window.addEventListener!");
callbackWrap(Element.prototype, "addEventListener", 1, logWrapper, "wrapped a Element.addEventListener!");
callbackWrap(Document.prototype, "addEventListener", 1, logWrapper, "wrapped a Document.addEventListener!");

Here’s a live example. (edit: the button example seems to be broken in Firefox)

The first thing callbackWrap does is save the original function (window.setTimeout, for this example) in a local variable, “original”, since we’ll need it later. We then replace the original with a new function. When this new function is called (the new window.setTimeout), we first call the “wrapperMaker” function (“logWrapper” in the example), passing it the callback function, which is the argument at the argumentIndex position, and the optional “extra” argument. That function returns a new function which replaces the original callback argument, before we then call the original function (saved in the local variable “original”) with the same arguments (except the callback is now wrapped).

So really this blog post should have been called “a function that wraps other functions such that all callback functions passed to it are wrapped by yet another function”. There’s two levels of wrapping going on: the original function is wrapped, such that it wraps every callback given to it. If you’re confused I don’t blame you.

Why would I want to do this, you ask? There are a couple scenarios I had in mind, and I’m sure you can think of others.

First, I wanted to catch all uncaught exceptions for a debugging tool I’m working on. Sure, you can assign an error handler to the “onerror” property of the window object, but this only gives you the error name, file name, and line number – I wanted the full exception object to be caught by a try/catch.

Here’s a wrapper that catches all uncaught exceptions and alerts them:

function exceptionWrapper(func, extra) {
    return function() {
        try {
            return func.apply(this, arguments);
        } catch (e) {
            alert(e);
        }
    }
}

Second, in Cappuccino we mimic Cocoa’s concept of a “run loop”, but due to the way browsers work the implementation is a bit different. A consequence of this was that we couldn’t automatically call “[[CPRunLoop currentRunLoop] performSelectors];” at the end of each run loop, which is required for various pieces of Cappuccino. If you’ve ever come across a situation where you perform some action but the UI doesn’t update until you move the mouse, it’s probably because performSelectors isn’t being called. This isn’t common, since Cappuccino encapsulates events, XMLHttpRequests, and now timers with CPEvent, CPURLConnection, and CPTimer, respectively. These Cappuccino classes handle calling performSelectors for you. However, if you wanted to integrate with a third party library or use setTimeout, XMLHttpRequest, etc directly, currently you would need to call performSelectors manually. With this new trick we can call it automagically.

Here’s the wrapper that does exactly that (note the inline Objective-J call to “[[CPRunLoop currentRunLoop] performSelectors]”):

function performSelectorsWrapper(func, extra) {
    return function() {
        var result = func.apply(this, arguments);
        return [[CPRunLoop currentRunLoop] performSelectors];
    }
}

One minor feature I didn’t demonstrate was that callbackWrap returns the original function that it wrapped. If you need the original for any reason you can save it to some other variable.

callbackWrap could use a few improvements. Currently this breaks on cases where you pass a string instead of a function. A simple check for the argument type, and appropriate handling would solve this (either skipping the wrapping, or compiling the the string with a “new Function()” call). But using strings instead of functions is considered poor practice anyway.

Improved Browser Paint Events Bookmarklet

John Resig posted today about a nifty new feature available in Firefox nightlies, browser paint events. He also posted an example script and bookmarklet called TrackPaint. He goes into greater depth in his post, so I won’t bother here.

I wanted something more “real-time” and closer to the Quartz Debug utility included with the Mac OS X developer tools (which essentially provides this feature for all of OS X), so I present my modified bookmarklet and code:

// modified from John Resig’s example: http://ejohn.org/apps/paint/track.js
(function(){
    var container;
    
    window.addEventListener("MozAfterPaint", log, false);
    
    if ( document.body )
        bind();
    else
        window.addEventListener("load", bind, false);
        
    function bind()
    {
        container = document.createElement("div");
        document.body.appendChild(container);
    }

    function log(e)
    {
        window.removeEventListener("MozAfterPaint", log, false);

        var rects = e.clientRects;

        for ( var i = 0; i < rects.length; i++ ) {
            var rect = rects[i];
            var div = document.createElement("div");

            with (div.style) {
                background = "red";
                opacity = "0.1";
                position = "absolute";
                top = rect.top + "px";
                left = rect.left + "px";
                width = (rect.right – rect.left) + "px";
                height = (rect.bottom – rect.top) + "px";
            }

            container.appendChild(div);
        }
        
        window.setTimeout(function() {
            while (container.firstChild)
                container.removeChild(container.firstChild);
            
            window.setTimeout(function() {
                window.addEventListener("MozAfterPaint", log, false);
            }, 0);
        }, 100);
    }
})();

Rather than recording each event and displaying them when you click, this version immediately disables the MozAfterPaint event listener (to avoid the recursion issue), shows the translucent red divs, waits 100 ms, removes the rectangles, and re-enables the MozAfterPaint event listener.

It will miss some events during the 100 ms flash, but overall it seems to work pretty well. You could modify it to re-enable the event listener between adding and removing the divs, but I’m not sure it’s worth the effort.

YouTube Fullscreen Bookmarklet

I find it incredibly annoying when an embedded YouTube video can’t be made fullscreen, and I have to switch to YouTube.com just to watch it.

So, I wrote this simple little bookmarklet which modifies the embed code for any YouTube videos to allow fullscreen. It could also easily be made into a user script for GreaseMonkey, etc, to perform the modifications automatically.

Bookmarklet

Source:

var os = document.getElementsByTagName("object");
for (var i = 0; i < os.length; i++)
{
    var o = os[i].cloneNode(true);
    o.innerHTML = ‘<param name="allowFullScreen" value="true"></param>’ + o.innerHTML;
    for (var j = 0; j < o.childNodes.length; j++)
    {
        if (o.childNodes[j].name == "movie")
            o.childNodes[j].value += "&fs=1";
        else if (o.childNodes[j].nodeName.toUpperCase() == "EMBED") {
            o.childNodes[j].src += "&fs=1";
            o.childNodes[j].setAttribute("allowfullscreen", "true");
        }
    }
    os[i].parentNode.replaceChild(o, os[i]);
}

Try it out on this page (I’m too lazy to actually make it fullscreen).

Note that currently it doesn’t actually check to make sure it’s a YouTube video that it’s modifying, so it might stomp all over other types of embeds.

Multitouch JavaScript "Virtual Light Table" on iPhone v2.0

Now that iPhone 2.0 is out I started playing around with some of the new web features, and soon found that I had created the prototypical virtual light table that’s an essential demo for any new multitouch technology.

It’s about 100 lines of JavaScript. It grabs the 10 latest photos from Flickr’s “interesting photos” API and randomly places them on the screen for you to play with:

This is great if you have an iPhone with the 2.0 software, but desktop browsers should get some multitouch love too. So I started writing a little bridge that fakes multitouch events in desktop browsers. It’s far from complete, but it’s just good enough to get the virtual light table demo working.

So go ahead and load it up in the new iPhone MobileSafari or Safari 3.1+ / WebKit nightly (requires CSS transforms):

http://tlrobinson.net/iphone/lighttable/

In desktop browsers it uses the previous clicked location as a second “touch”, so you can click a photo then click and drag another spot on the photo to resize and rotate (notice the yellow dot).

For a good overview of touch events and gestures, check out this SitePen blog post and Apple’s documentation.

Here’s the source for the fake multitouch bridge:

http://tlrobinson.net/iphone/lighttable/multitouch-fake.js.

Clearly the reverse of this bridge would be even more useful, since iPhone only sends mouse events under specific conditions. The mousedown, mouseup, and mousemove events could be emulated using the touch equivalents to make certain web apps work on the iPhone without much additional work. Of course you would need to either cancel the default actions (i.e. panning and zooming) on touch events, or have some way to manage the interactions between them.

Mac OS X, Web Sharing / Apache, and Symlinks

Mac OS X comes with an Apache installation which is very handy, but by default it’s configured not to follow symlinks. A lot of times I have projects in other directories which I want to share via the web server, but end up getting errors such as the following:

Forbidden

You don’t have permission to access /~tlrobinson/Editor/ on this server.

And in the error log file:

[Wed Jun 25 16:17:14 2008] [error] [client ::1] Symbolic link not allowed or link target not accessible: /Users/tlrobinson/Sites/Editor

To enable following of symlinks, edit your account’s configure file located at /private/etc/apache2/users/username.conf

Here’s the default:


Options Indexes MultiViews
AllowOverride None
Order allow,deny
Allow from all

You can either add “FollowSymLinks” to the Options directive (“Options Indexes MultiViews FollowSymLinks”), or change the AllowOverride directive to “All” (“AllowOverride None”) and place a .htaccess with it’s own Options directive (“Options FollowSymLinks”) in your Sites directory.

Then just restart Apache (“sudo apachectl graceful”) and symlinks should work.

Using user stylesheets to highlight links to PDFs or other media, rel="nofollow", etc

Browsers allow you to define your own stylesheet that’s applied to every page you visit. For the longest time I’ve wondered why anyone would ever want this feature. I figured it would be useful for people with poor vision or other disabilities and that was about it.

But combined with some neat features of CSS, one can come up with interesting uses of user stylesheets. Consider the following:

a[rel~="nofollow"] {
text-shadow: rgba(255,0,0,0.25) 1px 1px 1px;
}

This rule uses the partial attribute value selector to give all hyperlinks with the rel=”nofollow” attribute a slight red shadow (like the preceding link, if your browser supports text-shadow).

Why would you want this? Well, for me, pure curiosity. But SEOs or spammers may find it enlightening though.

For example, the first thing I noticed was that on the Hacker News homepage links to external sites newer than 3 or 4 hours have the nofollow attribute, but older ones do not – clearly a spam deterrent.

There are many other useful and interesting scenarios. Say you want to highlight all PDF or MP3 links (“$=” matches the end of an attribute):

a[href$=.pdf], a[href$=.mp3] {
text-shadow: rgba(0,255,0,0.25) 1px 1px 1px;
}

Or email links (“^=” matches the beginning of an attribute):

a[href^=mailto] {
text-shadow: rgba(0,0,255,0.25) 1px 1px 1px;
}

Note that I used text shadows, but anything styleable by CSS is fair game.

With April fools day approaching, one could imagine other creative uses. I’ll leave that as an exercise to the reader.

Ad-blocking and whyfirefoxisblocked.com

Recently it [came to the attention of the Digg masses](http://www.digg.com/software/Why_Firefox_is_blocked) that some slimy SEO guy was advocating web site owners block *every* Firefox user simply because Firefox allows ad-blocking plugins, and doesn’t provide web site owners with any way to block users of such plugins.

I find this incredibly silly for a number of reasons. The number of Firefox users who use such plugins is likely very small. By blocking *all* Firefox users, you not only keep the ad-blocking users away (who most likely wouldn’t click on your ads anyway), but also the much larger number of users who *might* click on your ads. Mmmmkay…

Even if he’s doing this out of principle, or to make a point, he apparently doesn’t realize that *every* popular browser has ad-blocking software available. See below.

Personally, I’ve realized that I’m completely web ad blind. After 10+ years of web browsing, I’ve subconsciously conditioned myself to ignore all web advertising, unless it’s something truly obnoxious like Flash ads with sound, etc.

That said, this guy has inspired me to install both ad blocking software, and plugin to change the browser’s user-agent string to get around silly browser-specific filters (although if a site resorts to blocking certain browsers, do you really want to support them?).

### Ad Blocking ###

Firefox: [Adblock Plus](http://adblockplus.org/), also available from the Firefox plugin directory.

Safari: [PithHelmet](http://www.culater.net/software/PithHelmet/)

### User-Agent Changing ###

Firefox: [User Agent Switcher](https://addons.mozilla.org/en-US/firefox/addon/59)

Safari: built in, enable Safari “Debug” menu by entering the following on the command line:
defaults write com.apple.Safari IncludeDebugMenu 1

Update: the ad-blocking debate got picked up by [at least one mainstream newpaper](http://www.nytimes.com/2007/09/03/technology/03link.html), surely causing a surge of new Ad-block users… not quite what the slimy SEO guy had in mind. Karma?