• Piranhas: Now with Amazon.it support

    Piranhas now has full support for Amazon.it in addition to Book Depository, Wordery, and the other five Amazon stores.

    I’ve also checked and updated the shipping rates data for all the supported Amazon stores, so depending on your location you may see more accurate estimates of the shipping costs now.

  • Retrospective: Ilves IPA v2

    Ilves IPA v2 bottle and glass

    Ilves IPA v2 was the second iteration of the first beer I ever brewed. As I overwrote my original Ilves IPA recipe when I redesigned it, I’m not entirely certain what I changed for this second run at it, but I’m pretty sure it mostly consisted of changes to the hopping additions and schedule.

    Now, almost two years later, it doesn’t really taste all that much like an IPA. Who would have guessed that storing hop heavy pale ales for years wouldn’t be a great idea?

    It has a pleasant but very mild hop aroma on the nose. The flavour is still mildly hoppy, but dominated by the malt character. I think there might be a slight vague, unidentifiable off-flavour in there too, but that might just be a result of how long it’s been stored in somewhat nonoptimal conditions.

    What to take away from this and my other retrospectives of pale ales? For one thing, I’ve learned firsthand that there isn’t much point in hoarding bottles of pale ales for years…

  • Retrospective: Little Rascal

    Little Rascal bottle and glass

    Brewed and bottled in March-April 2014, Little Rascal is an ESB based on one of my brother’s recipes.

    I can’t remember what this beer was like in 2014 as I don’t have any real recollection or tasting notes about it, but today the best you can say is that it’s a light, drinkable beer.

    Visually it’s surprisingly cloudy, especially considering how long it’s spent in the bottle (though not under ideal circumstances).

    There isn’t any particularly wrong with it. No odd off flavours or major flaws, it’s just a fairly inoffensive beer. Not that it really matters since I’m drinking the last bottle in existence as I write this…

  • Retrospective: Ahma Ale

    Ahma Ale bottle and glass

    This was the second beer I brewed. Ever.

    Back in 2014 this was an IPA, not so much anymore. All the hop bitterness and aroma seems to have disappeared and the flavour profile is very much on the malty side. Overall this is still a surprisingly drinkable beer, despite it’s age and my lack of experience back in 2014.

    It’s definitely better than the Ilves IPA I cracked open at the beginning of last year… Come to think of it, there’s a fairly strong possibility that this last bottle of Ahma Ale has been sitting in my fridge for the best part of a year at this point since I’ve been really lazy about writing it up.

    Lastly, I’d like to point out that my labels are better designed these days, or at least I like to think so…

  • My favourite books of 2015

    In the vein of my 2013 and 2014 lists, here are a few of my favourite books of 2015 (in no particular order). That is, books that that I read in 2015, not books that were necessarily published in 2015.

    Digital Apollo: Human and Machine in Spaceflight

    Digital Apollo

    Digital Apollo by David Mindell tells the story of the amazing technology behind the Apollo lunar missions. It also delves into the debate (or even fight) between engineers and astronauts at NASA at the dawn of the space age. The full books is definitely worth reading, but the gist of it is that the engineers wanted to automate as much as possible of the flights and the astronauts wanted as much control as possible.

    A Man on the Moon

    A Man on the Moon

    Recommended to me on Reddit by Brady Haran, A Man on the Moon by Andrew Chaikin is possibly the single accounting of the Apollo lunar missions that you’ll find within a single set of covers. Based on interviews with 23 of the 24 Apollo astronauts.

    The “Imperial Radch” series

    The “Imperial Radch” series book covers

    At the beginning of the year I stumbled across the first book of the Imperial Radch series, Ancillary Justice by Ann Leckie. Originally published all the way back in 2013, I found Ancillary Justice to be a totally engrossing take on a science fiction space opera.

    The perspective of the protagonist, a not entirely human, kind of ex-spaceship, ex-soldier Breq is really interesting. Breq is also from a culture which doesn’t distinguish between gender which adds an interesting extra twist to the storytelling.

    If you enjoy Ancillary Justice, you should definitely go on to read the next two novels in the series too (Ancillary Sword and Ancillary Mercy)

    The Martian

    The Martian

    If you haven’t heard of The Martian (by Andy Weir) until now then I think that counts as a minor miracle of some kind. I’m pretty sure I devoured the entire book over three nights or so (usually reading until it was way too late for a work night). Even if you saw the movie, I think it might be worth reading the book (at least if you’re at all a geeky or nerdy type of person).

    Double Cross: The True Story of the D-Day Spies

    Double Cross: The True Story of the D-Day Spies

    Ben Macintyre’s Double Cross is about the German and Allied spies of the second World War and about how the allies (and especially the British) managed to turn almost all German spies into double agents. It’s an amazing story and at times even hard to believe since the facts read a bit too much like a le Carré novel.

  • What What Wit v2

    What What Wit v2 bottle and in glass

    This is the second version of my What What Wit (originally based on a recipe in Randy Mosher’s Radical Brewing).

    The biggest changes were to the boil additions and my choice of yeast. The first version my my recipe used White Labs WLP575 (Belgian Style Ale Yeast Blend), largely out of necessity as that was the only wit yeast in stock at my brewshop when I was ordering my ingredients for it. This version used Wyeast 3944 (Belgian Witbier) instead.

    The recipe also gained some fresh grapefruit peel in addition to the fresh orange peel that I used originally. I ended up using a bit less orange peel than I intended to since I failed to buy enough oranges.


    The colour is a nice straw yellow and it has a nice bit of haze (as is expected in a Wit). Overall this is a very pleasant beer and rather good, even if I say so myself.

    In future versions I think I’ll add even more orange or grapefruit peel as I don’t think it comes through quite enough yet, otherwise the other spices (coriander and chamomile) seem to be nicely balanced. I’m not sure if using dried orange peel would be better or worse than using the fresh orange peel I’ve used so far…

    In any case, I’ll definitely make this beer again (or some slightly modified version of it)…

  • Building Apple TV apps with Middleman

    At Kisko Labs we were lucky enough to receive an Apple TV developer kit from Apple (two actually, because I got one for my personal Apple developer account too). Motivated by the free hardware, I took some time to learn how to develop for the new Apple TV (one TVML app and one “native” app). In this post I’ll walkthrough creating a TVML app with Middleman.

    Apple TV (4th generation)

    What is TVML/TVMLKit?

    In Apple’s words:

    The TVMLKit framework enables you to incorporate JavaScript and TVML files in your binary apps to create client-server apps.

    In other words your Apple TV app can download JavaScript and XML files from your server (or any HTTP server, we used S3 and CloudFront for our app). The Apple TV will automatically generate the UI for you based on the XML templates your provide.

    The apps you can create with TVMLKit are limited, but it looks perfect for media heavy applications (e.g. viewing videos or photos).

    If you’ve used an older 3rd generation Apple TV, the applications created with TVML will look very familiar…

    What do I need (to know) for this tutorial?

    Passing knowledge about creating sites with Middleman will suffice (I’m going to assume that you have a recent version installed). You should also have Xcode 7.1 installed and be vaguely familiar with using it. An actual Apple TV is not required (the simulator will suffice).

    The versions I used:

    • Xcode 7.1
    • Middleman 3.4
    • Ruby 2.2

    I also assume that you know how to navigate around and run commands in a terminal environment.

    What will this tutorial cover?

    Creating a new TVML app in Xcode, creating a simple backend for it with Middleman, and using the app to play videos from the Internet Archive’s 35mm Stock Footage collection.

    0. Initial setup

    Make sure that you have Xcode 7.1 and Middleman 3.4 installed. Then create a directory for the work in this tutorial:

    mkdir StockFootageTV
    cd StockFootageTV

    1. Create the Middleman app

    Start by creating a new Middleman app called backend in the directory you just created:

    middleman init backend
    cd backend

    We’ll be using Slim to generate the XML for us, so add the following line to the Gemfile:

    gem "slim", "~> 3.0.6"

    Once this is done, run bundle install.

    Then create a new file called application.js.coffee in the source/javascripts/ directory with the following contents:

    createAlert = (title, description) ->
      alertString = """<?xml version="1.0" encoding="UTF-8" ?>
      parser = new DOMParser
      alertDoc = parser.parseFromString(alertString, "application/xml")
    App.onLaunch = (options) ->
      doc = createAlert("Hello World", "This is a TVMLKit app")

    We’ll use this as the basis for our TVMLKit app. Next let’s set-up the project in Xcode. You can delete the existing all.js file if you wish, we won’t need it.

    2. Create the tvOS app

    Open Xcode and select Create a new Xcode project from the start screen (or File → New → Project from the menu).

    Create a new Xcode project

    In the next screen, choose to create a Single View Application for tvOS.

    Choose a template for your new application

    Set the product name to StockFootageTV and the language to Swift.

    Choose options for your new project

    Finally, save the project to the StockFootageTV directory you created in Step 0.

    At the end of this step, you should have a directory structure that looks something like this (with a lot more files):

    ├── StockFootageTV
    │   ├── StockFootageTV
    │   ├── StockFootageTV.xcodeproj
    │   ├── StockFootageTVTests
    │   └── StockFootageTVUITests
    └── backend
        ├── Gemfile
        ├── Gemfile.lock
        ├── config.rb
        └── source

    You can test that the Xcode project is working by hitting ⌘ + R in Xcode (you should get an Apple TV simulator with a blank screen).

    3. Do some tedious set-up work in Xcode

    Before we can crack on with our awesome TVML app, we need to do some chores in Xcode.

    First of all, delete the ViewController.swift and Main.storyboard files from the project (select Move to Trash when Xcode asks).

    Then select the project in the left sidebar, choose the General tab, and clear the Main Interface box:

    Main Interface

    Finally, open the Info.plist file from the left sidebar, right click and click Add Row and paste in NSAppTransportSecurity. It should automatically expand to “App Transport Security Settings” and the Type should be set to Dictionary.

    Click on the arrow to expand the entry and add a entry with the key NSAllowsArbitraryLoads (or “Allow Arbitrary Loads” in English). Set the value to YES.

    Info.plist edits

    4. Set up the tvOS app to load application.js

    First of all, start the Middleman development server:

    bundle exec middleman server

    Go to http://localhost:4567/javascripts/application.js to check that the JavaScript actually loads correctly.

    Then open AppDelegate.swift in Xcode and replace its contents with the following (you can leave the comments at the top of the file as they are):

    import UIKit
    import TVMLKit
    class AppDelegate: UIResponder, UIApplicationDelegate, TVApplicationControllerDelegate {
        var window: UIWindow?
        var appController: TVApplicationController?
        let baseURL = "http://localhost:4567"
        func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
            window = UIWindow(frame: UIScreen.mainScreen().bounds)
            let context = TVApplicationControllerContext()
            let javaScriptURL = NSURL(string: "\(baseURL)/javascripts/application.js")!
            context.javaScriptApplicationURL = javaScriptURL
            context.launchOptions["BASEURL"] = baseURL
            appController = TVApplicationController(context: context, window: window, delegate: self)
            return true

    Save the file and run the app again with ⌘ + R. You should be greeted with the following view in the Apple TV simulator:

    Hello World!

    Good Job! You now have a working, albeit useless, tvOS app!

    5. Generate some XML

    Since we don’t want to write out all the entries by hand, let’s create a YAML file with a list of our videos. In your Middleman app, create a new file called data/content.yml directory (create the data directory too, if you don’t have it already).

      - title: "Various videos"
          - title: "Downtown Los Angeles streets"
            description: "Downtown Los Angeles streets, process plates, color."
            url: "https://archive.org/download/PET0981_R-2_LA_color/PET0981_R-2_LA_color_720p.mp4"
            preview: "https://archive.org/download/PET0981_R-2_LA_color/PET0981_R-2_LA_color.thumbs/PET0981_R-2_LA_color_000027.jpg"
          - title: "Hot Rods, Southern California, 1940s"
            description: "Scenes at Southern California racetrack with hot rods and drivers."
            url: "https://archive.org/download/27EG-28-EG-58_HOTRODS/27EG-28-EG-58_HOTRODS_720p.mp4"
            preview: "https://archive.org/download/27EG-28-EG-58_HOTRODS/27EG-28-EG-58_HOTRODS.thumbs/27EG-28-EG-58_HOTRODS_000027.jpg"
          - title: "Internet Archive 35mm Stock Footage Sample Reel"
            description: "This reel shows samples from Internet Archive's 35mm Stock Footage collection."
            url: "https://archive.org/download/InternetArchive35mmStockFootageSampleReel/IA35mmSampleReel_720p.mp4"
            preview: "https://archive.org/download/InternetArchive35mmStockFootageSampleReel/InternetArchive35mmStockFootageSampleReel.thumbs/IA35mmSampleReel_000054.jpg"
      - title: "Comedy"
          - title: "The Mechanic (Part 1)"
            description: "Silent comedy taking place in an automobile garage."
            url: "https://archive.org/download/AFP-19-OJ_R-2_TheMechanic_A/AFP-19-OJ_R-2_TheMechanic_A_720p.mp4"
            preview: "https://archive.org/download/AFP-19-OJ_R-2_TheMechanic_A/AFP-19-OJ_R-2_TheMechanic_A.thumbs/AFP-19-OJ_R-2_TheMechanic_A_000054.jpg"
          - title: "The Mechanic (Part 2)"
            description: "Silent comedy taking place in an automobile garage. 2/2"
            url: "https://archive.org/download/AFP-19-OJ_R-2_TheMechanic_B/AFP-19-OJ_R-2_TheMechanic_B_720p.mp4"
            preview: "https://archive.org/download/AFP-19-OJ_R-2_TheMechanic_B/AFP-19-OJ_R-2_TheMechanic_B.thumbs/AFP-19-OJ_R-2_TheMechanic_B_000005.jpg"

    Then create a new file called videos.xml.slim in the source directory. Add the following contents to it:

    doctype xml
          title 35mm Stock Footage
          - data.content.video_sections.each do |video_section|
                title= video_section.title
                decorationLabel= video_section.videos.size
                      - video_section.videos.each do |video|
                        lockup videoURL=video.url
                          img src=video.preview width=500 height=308
                          title= video.title
                          description = video.description

    Then open up the config.rb file, and configure Middleman not to use layouts for XML files by adding the page "*.xml", layout: false line to the Page options, layouts, aliases and proxies section of the file.

    # ... snip ...
    # Page options, layouts, aliases and proxies
    page "*.xml", layout: false
    # ... snip ...

    Finally, open http://localhost:4567/videos.xml in your browser to ensure that the XML is being generated correctly.

    videos.xml in Safari

    If you’ve done everything correctly, the backend directory should have the following contents:

    ├── Gemfile
    ├── Gemfile.lock
    ├── config.rb
    ├── data
    │   └── content.yml
    └── source
        ├── images
        │   ├── background.png
        │   └── middleman.png
        ├── index.html.erb
        ├── javascripts
        │   └── application.js.coffee
        ├── layouts
        │   └── layout.erb
        ├── stylesheets
        │   ├── all.css
        │   └── normalize.css
        └── videos.xml.slim

    6. Load the XML from our JavaScript

    Open the application.js.coffee file again and replace it with the following:

    createAlert = (title, description) ->
      alertString = """<?xml version="1.0" encoding="UTF-8" ?>
      parser = new DOMParser
      alertDoc = parser.parseFromString(alertString, "application/xml")
    readBody = (xhr) ->
      data = undefined
      if !xhr.responseType or xhr.responseType == 'text'
        data = xhr.responseText
      else if xhr.responseType == 'document'
        data = xhr.responseXML
        data = xhr.response
    App.onLaunch = (options) ->
      xhr = new XMLHttpRequest
      xhr.onreadystatechange = ->
        if xhr.readyState == 4
          xml = readBody(xhr)
          console.log xml
          parser = new DOMParser()
          doc = parser.parseFromString xml, "application/xml"
          doc.addEventListener "select", (event) ->
            el = event.target
            videoURL = el.getAttribute("videoURL")
            if videoURL != null && videoURL != ""
              player = new Player()
              playlist = new Playlist()
              mediaItem = new MediaItem("video", videoURL)
              player.playlist = playlist
      xhr.onerror = ->
        errorDoc = createAlert("Evaluate Scripts Error", "Error attempting to evaluate external JavaScript files.")
      xhr.open "GET", "#{options.BASEURL}/videos.xml", true
      xhr.send null

    This is adds a readBody helper to make handling XHR responses a bit easier and sets up the application to load our videos.xml file. Note that for some reason tvOS applications require a fully qualified URL when loading resources (you can’t just read /videos.xml).

    7. Try it out

    Now if everything’s gone right, you can go back to Xcode and run the app in the simulator again with ⌘ + R. You should see a more useful tvOS app! To navigate around, enable the Apple TV Remote from the Edit menu.

    The final app in the simulator

    Get the project files

    You can find the project files on GitHub:

  • Piranhas for iOS 1.1

    Piranhas for iOS version 1.1 is now available on the App Store.

    In addition to native book cover previews this release also contains some minor bug fixes.

    Piranhas helps you save money by comparing prices between Amazon stores, the Book Depository, and Wordery. It’s super easy because we calculate the shipping costs and currency conversions for you.

    Download on the App Store

    Or, alternatively, go to www.piranhas.co to use Piranhas in your browser.

  • Saukko Stout Revisited

    Last weekend I took a trip to nostalgia land and cracked open a bottle of one of the first beers I ever made: Saukko Stout.

    Saukko Stout bottle and pint

    Saukko Stout was my third beer, brewed all the way back in February 2014 (bottled on March 2014). This means that it had been bottle conditioning for about 18 months at this point (and not in any particularly optimal setting).

    Considering its age and storage conditions (and the fact that it was one of my first beers), it was actually pretty decent. I’m not sure I’ll be rushing off to brew another gyle of it, but it was eminently drinkable and enjoyable. Definitely far better than the bottle of Ilves IPA I had back in January at any rate…

    PS. Check out my free iOS apps Beer Styles 2 and Piranhas for iOS

  • Beer Styles 2

    Beer Styles 2 has been available in the App Store for a few days now. Beer Styles 2 is a big update and has several swell improvements, especially for iOS 9 devices.

    BJCP 2015 and 2008 guidelines

    2015 and 2008 guideline switcher

    Just like the previous version this includes both the 2008 and 2015 guidelines (and quite a few small formatting and typo corrections).

    Slide Over and Split View

    On iOS 9 you can use Slide Over and Split View on iPads to multitask while browsing style guidelines. Very handy if you’re trying to build a recipe in one app while referring to the style guideline!

    Beer Styles in a Split View

    Spotlight search integration

    Beer Styles now has Spotlight integration so you can search for style guidelines without having to first launch the app. Just swipe down on the home screen…

    Beer Styles Spotlight search

    Nicer sharing

    Sharing individual styles is now nicer because your friends can now see the same view as you do, even if they don’t have Beer Styles installed or if they don’t even have an iOS device.

    Beer Styles on the web

    Still free

    There’s still one thing that hasn’t changed: Beer Styles is still completely free!

    Download on the App Store

    PS. If you like Beer Styles (or even if you don’t), you might like to try my latest iOS app: Piranhas for iOS. Piranhas is a free book price comparison tool for the web and iOS.

    Oh, and if you like using Beer Styles, a review on the App Store would be highly appreciated…