1. Got lightblue+bluez set up on the raspberry pi, successfully paired and connected with Macbook. Not so much success communicating, sockets only worked one way, and the OS X doesn’t seem to be able to connect to services advertised on the pi despite being able to see that they exist. Also got started with USB programming in python with pyusb — is complex, but less so than I expected.

  2. When using to send content-disposition: attachment responses, you MUST explicitly set the response encoding (charset) otherwise windows will assume the response is in whatever-weird-encoding-windows-uses, rather than UTF-8 (you are using UTF-8, aren’t you?).

    CSV example code:

    response = HttpResponse(utf_8_encoded_csv_text, status=200, mimetype="text/csv; charset=utf-8")
    response['Content-Disposition'] = 'attachment; filename=data.csv'

    It seems that some weird old applications like SPSS need a BOM in there as well, even though UTF-8 doesn’t have a BOM. Add that like this

    response.content = '\xef\xbb\xbf' + response.content

    before sending the response

    return response
  3. Emil Björklund: #PHP folks: when fetching from an API, would it be wise to use function_exists to check for cURL, and else fall back to file_get_contents()?

    @thatEmil that should work fine — one thing to bear in mind is that by default they both treat redirects differently. IIRC, cURL doesn’t follow redirects by default whereas file_get_contents will.

  4. New in this version of :

    • Improved styling (still WIP, as always)
    • stream on homepage, currently just notes but will add other things too
    • content creation/editing UIs publicly viewable (take a peek!)
    • profile photo as the icon
    • complete code restructure, now using silex for HTTP routing
    • removed tonnes of nonsense framework code, replaced with small number of ≈200 line functional libraries. Clearer, easier to navigate and much more fun to work with
    • no more SQL databases — content is indexed using a custom built 209 LOC CSV index which is surprisingly speedy, and suits my needs perfectly
    • no more support for rendering content in many forms using content negotiation (HTML, JSON, ATOM etc.) — now only HTML+microformats2 representations of content are given
    • ATOM feed shimmed with microformats2 to ATOM converter
    • Pingbacks no longer natively accepted (though they are sent), using webmention.io to shim them into webmentions for easier handling

    The local maximum has been overcome, for now. There is still much to do.

  5. psysh.org is the REPL shell we have been waiting for. How to start an interactive shell with a given context:

    require 'vendor/autoload.php';
    $app = require 'src/app.php';
    Psy\Shell::debug(['app' => $app]);

    Supports readline, pcntl, registering custom commands, automatic semicolon insertion, clean+concise string representations of evaluated values. Amazing work Justin Hileman!

  6. Had many basic software development lessons hammered in by personal experience over the last couple of years: hierarchy bad. side effects bad. many moving parts bad. undue complexity bad. inconsistency bad. SQL databases fragile. always be reducing.

    It’s amazing just how seductive complex, unproductive tools can be. Successfully overcome+abandoned:

    • Codeigniter
    • Doctrine ORM
    • Bootstrap
    • Backbone, Ember, Angular
    • Symfony Security component

    PHP remains productive and speedy (with composer, delightful dependency management), python nice with some irritations. jQuery useful when absolutely necessary, plain with small libraries loaded via requirejs handle most progressive enhancement concisely. node.js nice for some things, preferring go’s approach to async programming but still not much everyday need for it.

    Avoiding middlemen: LESS, SASS, Coffeescript. Unnecessary for most of my work, and more moving parts is bad.

    Now bothering me is the frameworky nonsense accumulating in . Need to cleanse.

  7. Cut a process which was taking 20 mins down to 40 seconds — moral of the story is: building systems which allow you to see the system work in real-time and get an intuitive sense for how long things take is more effective than poring over SQL logs trying to figure out what on earth’s going on in retrospect.

  8. @|p^): Here I am at 5am, deciding to learn recursive functions in python, @gakera & @Hvitur_Hrafn I blame you both!

    @w03_ recursive functions are fun. Once you’ve figured them, closures and first-class functions out you’re pretty much there :)

  9. John Nye: @BarnabyWalters last time I used mozilla it was poor experience (2011), but validation of extensions was a manual process by someone.

    .@john_nye all the stores I’ve submitted extensions to do manual reviews. Mozilla:

    • gives two review options (fast and slow),
    • runs loads of automated tests in a web interface to suggest things to fix,
    • gives you the choice of which review to use, and creates a public URL from which the extension can be installed while the review’s in process

    Safari and Opera have fairly basic, boring forms for uploading stuff, and are extremely picky and unclear about exact image sizes for screenshots and icons. There’s also no “review in progress” page, but otherwise acceptable.

    Obviously I’ve not been able to actually submit an extension to the Chrome store, but I’d hope that it’s a damned good experience for $5. If they are doing automatic reviews, then the price becomes even more counter-intuitve. If they’ve automated it, surely it’s cheaper and quicker for them?

  10. Jack Way: @BarnabyWalters I think it's to authenticate devs and reduce spam.

    .Jack Way no other extension store (mozilla, apple, opera) demands payment, or requires it for verification. Also, Mozilla offers a far superior extension upload experience. Google has no excuse :)

  11. And the lesson of the day is: bean.fire(el, 'click') doesn’t work in Firefox Nightly, but turns out it’s unnecessary, because HTMLElement.click() does exactly the same thing and already works cross-browser. Always use the browser-native APIs if you can.

  12. I get a little annoyed at every now and again (grr package management) but then I come across things like nested tuple unpacking which are just so lovely they make up for it:

    for i, (key, value) in enumerate(list_of_tuples):
        print i, key, value
  13. I just faked having a task queue for note posting tasks using Symfony HttpKernel::terminate() and it was the easiest thing ever.

    Instances or subclasses of HttpKernel have a terminate($request, $response) method which, if called in the front controller after $response->send(); triggers a kernel.terminate event on the app’s event dispatcher. Listeners attached to this event carry out their work after the content has been sent to the client, making it the perfect place to put time-consuming things like POSSE and webmention sending.

    Once you’ve created your new content and it’s ready to be sent to the client, create a new closure which carries out all the the time consuming stuff and attach it as a listener to your event dispatcher, like this:

    $dispatcher->addListener('kernel.terminate', function() use ($note) {
        $note = sendPosse($note);

    Then, provided you’re calling $kernel->terminate($req, $res); in index.php, your callback will get executed after the response has been sent to the client.

    If you’re not using HttpKernel and HttpFoundation, the exact same behaviour can of course be carried out in pure PHP — just let the client know you’ve finished sending content and execute code after that. Check out these resources to learn more about how to do this:

    Further ideas: if the time consuming tasks alter the content which will be shown in any way, set a header or something to let the client side know that async stuff is happening. It could then re-fetch the content after a few seconds and update it.

    Sure, this isn’t as elegant as a message queue. But as I showed, it’s super easy and portable, requiring the addition of three or four lines of code.