June 10, 2013

deviator-sydney.png

Deviator, the show I worked on with PVI Collective and friends, is playing in Sydney, Australia starting tomorrow night. Get in there, tickets sell fast!

March 18, 2013

sunset-newhouse.jpg

These days I am using Bitbucket for the git repository hosting and task management on my commercial projects. One thing I often need to do is fetch a list of current tasks so that I can update a client with what is on our current agenda for them, get feedback about priorities etc. Here's a short Python script I hacked together to do that based on some other public domain scripts I found out there:

import base64
import cookielib
import urllib2
import json

class API:
    api_url = 'http://api.bitbucket.org/1.0/'

    def __init__(self, username, password, proxy=None):
        encodedstring = base64.encodestring("%s:%s" % (username, password))[:-1]
        self._auth = "Basic %s" % encodedstring
        self._opener = self._create_opener(proxy)

    def _create_opener(self, proxy=None):
        cj = cookielib.LWPCookieJar()
        cookie_handler = urllib2.HTTPCookieProcessor(cj)
        if proxy:
            proxy_handler = urllib2.ProxyHandler(proxy)
            opener = urllib2.build_opener(cookie_handler, proxy_handler)
        else:
            opener = urllib2.build_opener(cookie_handler)
        return opener

    def get_issues(self, username, repository, arguments):
        query_url = self.api_url + 'repositories/%s/%s/issues/' % (username, repository)
        if arguments:
            query_url += "?" + "&".join(["=".join(a) for a in arguments])
        try:
            req = urllib2.Request(query_url, None, {"Authorization": self._auth})
            handler = self._opener.open(req)
        except urllib2.HTTPError, e:
            print e.headers
            raise e
        return json.load(handler)

if __name__ == "__main__":
    import sys
    if len(sys.argv) < 5:
        print "Usage: %s username password baseuser repository" % (sys.argv[0],)
    else:
        result = API(sys.argv[1], sys.argv[2]).get_issues(sys.argv[3], sys.argv[4], (("status", "new"), ("status", "open"), ("limit", "50")))
        for p in result["issues"]:
            print " *%s %s" % (p.has_key("responsible") and "**" or "", p["title"])
            #print p["content"]
            print

Run it to get a usage message.

I secretly wish that bzr had won the distributed version control wars because of its superior user interface, but these days I am resigned to using git because pretty much everybody I have to inter-operate with is using it. It's not that bad.

Feb. 20, 2013

Pac-Man Ghost

You can run a single-use instance or site specific browser using Chrome web browser with it's own self-contained user data on GNU/Linux like this:

chromium-browser --app=https://plus.google.com/ --user-data-dir=$HOME/.chromium-googleplus

This launches Chrome in an 'app' style window with just that particular web app visible (in this case, Google Plus) and no location bar, navigation buttons, etc. It isolates the browsing session from your other browsing preventing e.g. social networking sites from tracking you too effectively. If you are logged into Facebook in a regular browser for example, that company can tell every site you visit that contains a Facebook 'like' button or Facebook comments section. They are effectively gathering a comprehensive browsing history of every Facebook user who remains logged in. Do you want Facebook to know your browsing history?

It should be possible to do something very similar with Chrome for Windows and a batch file.

On Mac you can use Fluid if you want to pay for ease of use, or the same trick as above with Chrome by accessing the binary directly e.g. something like /Applications/Google Chrome.app/Contents/MacOS/Google Chrome --app=https://plus.google.com/ --user-data-dir=$HOME/.chrome-googleplus. Save that as a shell script for one-click access.

If you want to further anonymise your browsing (e.g. obscure your IP address for example) you might consider using software like Tor.

Jan. 26, 2013

Prediction: within 3 years the stylus will be the killer feature of Android tablets.

I'm talking about true stylus input via induction, not those capacitive styluses you can buy for the current crop of tablets.

HTC Flyer, Lenovo ThinkPad Tablet, Asus Eee Pad MeMo, and Samsung Galaxy Note are at the forefront of this wave of hybrid capacitive + inductive (e.g. finger + stylus input in separate channels) Android tablets.

Pretty soon we'll all be wondering how we managed on tablets that only had capacitive/finger input.

Note: the most cutting edge versions of Android support full stylus support. Maybe this will be one of the rare times Android beats iOS to a killer feature.

I've long anticipated a logographic / hand drawn social network or micro-blogging platform where status updates come in the form of sketches. Maybe the upcoming stylus ubiquity will bring it about?

Dec. 10, 2012

  • Use zepto.js not jQuery.
  • Use -webkit-transition and -webkit-transform wherever possible.

Especially useful if you are developing with PhoneGap/Cordova on iPad and iPhone, or Android. Those webkit transforms saved my bacon on a recent iPad project. Here is the basic CSS you want to put on an element you want to optimise:

-webkit-transition: -webkit-transform 0ms;
-webkit-backface-visibility: hidden;

Try replacing $(this).hide(); with a transform that moves the element off screen like this (might need overflow: hidden on your body tag):

$(this).css("-webkit-transform", "translateX(1500px)");

Then when you want to show the element again do this instead:

$(this).css("-webkit-transform", "translateX(0px)");

I also had great success replacing jQuery UI drag-and-drop code with something hand-rolled:

$(this).css("-webkit-transform", "translateX(" + relativeX + "px) translateY(" + relativeY + "px)");

Hope this helps you!