Category > tech

bit.lyify – A bit.ly extension for Safari 5

» 09 June 2010 » In development, tech » 4 Comments

Safari 5 was released yesterday, and with it came extensions – YEY. So I decided to see how easy it would be to create a simple extension for everyone’s favourite URL shortening service – bit.ly.

Turns it it was super-dooper simple. In fact, the obligatory home page took about twice as long to build as the extension!

Here’s the code (a bit stripped down), which is placed in a script block within the global HTML file. Feel free to poach, abuse or point out improvements:

    // Handle context menu command
    function handleCommand(/* Command */ event) {
        if (event.command === "net.telliott.bitlyify")
            var currentTab = safari.application.activeBrowserWindow.activeTab;
            var url = currentTab.url;
            
            if (typeof url !== "undefined") {
                minimize(url);
            }            
            else {
                alert("There was an error processing your request. Could not find the URL of the current tab.");
            }
    }
        
    function minimize(/* String */ url) {
        var request = new XMLHttpRequest();
        var login = safari.extension.settings.getItem("login");
        var apikey = safari.extension.settings.getItem("apikey");
        
        if (login == null || apikey == null) {
            alert("You must have an bit.ly login name and API Key to use this extension. See http://bit.ly/ for more information");
            alert("login: " + login + " apikey: " + apikey);
        }
        else {
            var encodedUrl = escape(url);
            var showInfoTab = safari.extension.settings.getItem("showInfoTab");
        
            request.open("GET", "http://api.bit.ly/v3/shorten?login=" + login + "&apiKey=" + apikey + "&longUrl=" + encodedUrl + "&format=txt");
            request.setRequestHeader("Cache-Control", "no-cache");
            request.onload = function() {
                var status = request.status;
                
                switch(status) {
                    case 200:
                        var minUrl = request.responseText;
                        if (showInfoTab === true) {
                            var newTab = safari.application.activeBrowserWindow.openTab();
                            newTab.url = minUrl+"+"
                        }
                        alert('Your minified URL is ' + minUrl);
                        break;
                    default: 
                        alert('Oh Noes, there was a problem with your request: We received status ' + status + ", " + request.responseText);
                        break;
                }
            }
            request.send();
        }        
    }

    // Listen for the context menu command
    safari.application.addEventListener("command", handleCommand, false);

There are a few extensions I’d like to add to this, particularly getting rid of all the alert()‘s, but for half an hours work I’m pretty pleased :)

The API seems really nice and well thought out (so far, I’ve not tried to do anything complicated) – particularly adding settings. Really simple and works really well IMO. Setting up auto-updating extensions should be a breeze too, although I’m not convinced I’ve got it working quite yet (for once Apple have failed at UX design here. The extensions section in Safari preferences has a box which tells you if updates are available for your extensions, but doesn’t seem to give any indication of if and when it’s gone off to find an update, if it failed to parse the update.plist file or to allow you to force look for an update. So I’m left in the dark as to whether or not it’s actually working – but I’ve had an update sitting there for half an hour without being told about it).

Also I think I’ve found a bug. On any Google site (and only Google sites, out of the 10 or so big name sites I’ve tried) the SafariBrowserTab instance doesn’t have it’s page or url properties set, meaning you can’t sniff the URL or access the SafariWebPageProxy. Very weird. I’m going to do some more investigations and will raise a bug with Apple if I think it’s needed.

Until then, enjoy bit.lyify, but don’t try and use it for Google sites :(

Continue reading...

Tags: , ,

Dojo Build System Example

» 02 March 2010 » In development, tech » 2 Comments

So one of the questions that comes up time and time again on the Dojo mailing list is how to get a build working.

Like most things Dojo, it’s not that hard, but the system is designed to be flexible enough to fit around your workflow as well as providing the bells and whistles needed to optimise for more advanced use cases. This has a couple of problems:

  1. Writing documentation is tricky – it’s hard to get the basics down and cover all the extras in the same document, and
  2. there’s a steep learning curve – as a newbie it’s hard to know which knobs to turn, which to ignore, and which to tinker with

Additionally in my experience working examples are easier to understand than written documentation. They allow you to play with the options and convert them incrementally to your project.

So I created a simple example, and added it to the Dojo wiki. You can find it here (new site) or here (old site). Hope it helps!

Continue reading...

Tags:

Volatile and Ordering

» 31 May 2009 » In development, tech » 1 Comment

I learned something interesting about the java volatile keyword the other day, and I thought I’d share it with the class.

First, some background:

What it does:

Volatile is a Java keyword which guarantees that any and every time the variable is read, you’ll get the most up to date version of the variable. This can be very useful in multi-threaded environments. Why volatile? From Dictionary.com (not in full):
vol⋅a⋅tile

  1. changeable; mercurial; flighty: a volatile disposition
  2. fleeting; transient: volatile beauty.

Simply put, the compiler is told not to let the bytes making up the volatile variable hang around in any registers or other forms of cache and so each time you ask to read this variable you’ll go get the most recent write from any thread.

The Java Memory Model requires that both fetch and store operations on 32-bit variables are atomic, but this does not apply to 64-bit operations – which can be considered as two 32-bit operations – unless the variable is volatile (or guarded by a lock). Thus, volatile variables also guarantee readiness/consistency for 64-bit primitives, e.g. longs and doubles.

What it doesn’t do:

Volatile variables do not guarantee atomicity, so compound functions like:

int x = 0;
int y = x++;

are not guaranteed to make y equal 1 as two threads running the above code simultaneously would cause problems (i.e. second line requires a ‘read x’, then an ‘increment x’. Another thread could change the value of x during that time).

With me so far? Good. Now, before I get to the interesting bit, quick recap on some concurrency pitfalls.

Bad code – Do not copy!

/*
 * Not threadsafe!
*/
public class Foo {
    private int x;
    private int a,b;

    public Foo {
        x = 0;
    }

    public void setX(int newX) {
        this.x = newX;
    }

    public void setAandB() {
        a = x+1;
        b = x+2;

        // This could fail!
        assert b > a;
    }

}

This could fail in (at least) a couple of ways. Well, it’s the same way really, but there’s a couple of points I want to make.

Firstly, and most obviously, in a multi-threaded situation the value of x could be changed between lines 17 and 18 by a call to the setX() method. Ooops! BANG. :(

Now, let’s say we realise that we only ever need to increment x by 2 (and never decrement). So we try and fix the problem above by removing setX() and instead use incrementX(), like so:

Bad code – Do not copy!

/*
 * Not threadsafe!
*/
public class Foo {
    private int x;
    private int a,b;

    public Foo {
        x = 0;
    }

    public void incrementX() {
        this.x = x+2;
    }

    public void setAandB() {
        a = x+1;
        b = x+2;

        // This could fail!
        assert b > a;
    }

}

As x can only be incremented, surely b must always be larger than a and the assertion will pass? Wrong! This can still fail because the Java Memory Model allows the compiler to change the order of code if there is no detectable change on the output of that single thread caused by doing so, regardless of how this might effect other threads.

That is to say, after compilation line 18 could be run before line 17. Now, your assertion will fail because, even tho the value of x can only ever increment, line 18 can be called first (b = 2), incrementX() may then be called from a second thread and then line 17 is called (a = 3). Ooops! BANG :(

But what’s this got to do with volatile variables, mrtom? Good question. And the answer is this.

Volatile variables force the compiler not to rearrange the order of your code.

So, if x is marked as volatile the second code sample will pass.

Better code – still not great mind!

/*
 * Not threadsafe, but the assertion will pass
*/
public class Foo {
    private volatile int x;
    private int a,b;

    public Foo {
        x = 0;
    }

    public void incrementX() {
        this.x = x+2;
    }

    public void setAandB() {
        a = x+1;
        b = x+2;

        // This could fail!
        assert b > a;
    }

}

Personally I don’t really like using volatile in this way. It’s unclear and fragile. I’d much rather use a synchronized block or an explicit lock. But maybe because of that I don’t use volatile very often and, due to this, don’t know much about volatile.

If anyone can think of a concrete use case where using volatile like this has advantages let me know. I suspect there may be some performance improvement over a standard synchronized block but I’ve not got any data to support this.

Better still

/*
 * Threadsafe
*/
public class Foo {
    private Object lock;

    private volatile int x;
    private int a,b;

    public Foo {
        x = 0;
    }

    public void incrementX() {
        synchronzied(lock) {
            this.x = x+2;
        }
    }

    public void setAandB() {
        synchronized(lock) {
            a = x+1;
            b = x+2;
        }

        // This can't fail anymore
        assert b > a;
    }

}

References/Further reading:

  1. Java Concurrency In Practise and
  2. Java Language Specification (third edition) 8.3.1.4

Continue reading...

Tags: , , , ,