Archive for February, 2010

Fungrim’s APA #1: Brewing

Today me and Jenna started our very first home-brew. It’s supposed to be an American Pale Ale, but considering this is our first time, I’d be happy with a Very Swedish Bastard Ale. The final recipe looked like this:

  • Batch size: 10L
  • 1.6 kg light dry malt extract
  • 0,1 kg crystal malt
  • 20 g Cascade (60 min)
  • 12 g East Kent Goldings (20 min)
  • 8 g Cascade (15 min)
  • 5 ml Irish Moss (10 min)
  • 12 g Amarillo (5 min)
  • 1 pkg American Ale II Yeast

Everything went smooth. Cooling took about 20 minutes in the bathtub. OG was 1065 which is slightly higher than estimated (1059), but we also lost a bit more water so that’s probably expected. In any case, I decided to let it stay at 1065 even though an APA should stay under 1060 (according to beer smith), I like strong beer :-) And now I’m patientlywaiting for the bubbles to arrive. And depending on how the yeast comes on I’ll move to the second fermentation in a week or so.Exciting stuff!

MLP XX: Douglas and Daniel

Time to close some tabs, this time on my perhaps greatest intellectual heroes. Daniel C Dennett and Douglas Adams.  Starting with Adams:

  • Is there an artificial god?” – Douglas Adams brilliant speech on Digital Biota 2 Cambridge U.K., September 1998. Fabulous stuff in a rambling typical Adamesque way. Including the famous puddle analogy and the ages of sand. Long read, but worth it.
  • “Parrots, the universe and everything” – A likewise rambling speech, but this time on video. Hilarious and reflective, just what we loved him for. And do read the book, it is rather nice.

And now Dennett:

  • “Free Will” – A lecture from Edinburgh University. This is, if you like, a short version of his book Freedom Evolves. Which you should read (I’m re-reading now).
  • “Thank Goodness” – Reflections on his near death experience (from an atheist’s perspective) and a moving thanks to the advancements of science and medicine we tend to take for granted these day. I don’t think I could be as hard on the theists though, but the man has a point.
  • “Autobiography, pt I” – And if you need more, here’s some on the man himself.

Enjoy!

Planning a First Brew

I’m thinking of starting my very first attempt to brew some beer. Seriously, how hard could it be? I blame it on the fabulous Gnoff, who introduced me to brewing, sparked my interest and, not the least, cooks some really good stuff. I mean, really, really good!

So what do I need? A huge pot? Ok. Some hops and malt? Ok, but let’s do malt extract for this first one. Hum… *scratches chin* There’s actually quite a list of things I’ll need, but thankfully, must of them can be reused elsewhere.After much reading at Swedish Home Brewer Association, I’ll try this:

  • an american style ale (APA)…
  • … but with some english trimmings (hops), lets say Cascade, Goldings and Amarillo
  • dry pale malt extract
  • small batch, say 10 litres
  • liquid yeast

Things to decide later:

  • starting the yeast on beforehand?
  • hops in order Cascade, Goldings, Amarillo, but how much of each?
  • one or two fermentation phases?
  • priming method

The very nice Humlegården now has a shopping list saved in my name. I just need to add a bottle filler, fermentation barrel and optionally (probably, being a complete nerd) BeerSmith and I’m set to go. I believe…. Here’s to hope!

Do I need to change battery on this thing?

So, the blog has had a small hiatus. Again. Well, it will probably happen in the future as well, but for now I’ll try to start it up for a time. Can you hear the motor slowly spinning to life again? The sound of procrastination, lovely!

A Google Analytics Plugin for Nexus

Note: this post is cross-posted on Cubeia.com.

Since Firebase Community Edition uses Maven heavily, I realized I’d like to track our Nexus repository in Google Analytics. The Nexus Book says that there exists such a plugin already, but apparently now one knows where it is. So here’s my attempt to write a simple one.

If you’re an impatient kind, here’s the source code.

I created the project  in Eclipse, instructions here.

Now, let’s start off with a “repository customizer” which is Nexus extension point we’ll use to insert a custom request processor into every repository…

public class GaTrackerRepositoryCustomizer implements RepositoryCustomizer {

    private final Logger log = LoggerFactory.getLogger(getClass());

    @Inject
    @Named("gaTracker")
    private RequestProcessor gaTracker;    

    @Override
    public void configureRepository(Repository rep) throws ConfigurationException {
        log.debug("Attaching tracker to: " + rep.getName());
        rep.getRequestProcessors().put("gaTracker", gaTracker);
    }

    @Override
    public boolean isHandledRepository(Repository rep) {
        boolean b = true;
        log.info("Handles repository '" + rep.getName() + "': " + b);
        return b;   
    }
}

Not too complicated. We’re using injection to get hold of the actual tracker components and we’re inserting it into all repostories.

Wait, all repositories? Yes, and it’s problem I haven’t really figured out yet. Ideally I’d like to track “hosted” repositories only. However, we’ve configured all our builds to use a few common development “groups” for convenience. However, Nexus seems to treat groups as first class members, so even though an artifact may be deployed in a hosted repository while accessed through a group, the request processor will not get notified for the hosted repository, only the group. I tend to see “groups” as equivalent to “views” in which case I’d expect the hosted repository to be called as well, but, no…

Now, let’s create a request processor which will react when someone “reads” a path in a repository.  We’ll take it in pieces…

@Named("gaTracker")
public class GaTrackerRequestProcessor implements RequestProcessor {

    public static final String GA_TRACKER_ID = System.getProperty("cubeia.nexus.gaTrackerId");
    public static final String GA_REFERER_URL =System.getProperty("cubeia.nexus.gaRefererUrl");

    private final Logger log = LoggerFactory.getLogger(getClass());

    private final JGoogleAnalyticsTracker tracker;    

    public GaTrackerRequestProcessor() {
        if(GA_TRACKER_ID == null) {
            String msg = "Missing system property 'cubeia.nexus.gaTrackerId'";
            throw new IllegalStateException(msg);
        }
        log.info("Creating new tracker, with id: " + GA_TRACKER_ID);
        tracker = new JGoogleAnalyticsTracker("nexus", "read", GA_TRACKER_ID);
        checkRefererUrl();
        adaptLogging();
    }

[...]

We configure the plugin via system properties (not too beautiful, I know), the “tracker id” is the google tracking code id and is mandatory, and the “refer url” will be set on the call to GA if available.  We’re using the JGoogleAnalytics library to call GA for us. Also, I’m being naughty and throwing an illegal state exception if the tracker id is missing, since GA updates every 24 hours we’d like to be notified on errors early.

There’s  two methods above, one sets the logging in the tracker code to use to slf4j logger instead and the other checks for and sets the referer URL:

private void adaptLogging() {
    /*
     * Adapt the logging to use slf4j instead.
     */
    tracker.setLoggingAdapter(new LoggingAdapter() {

        public void logMessage(String msg) {
            log.debug(msg);
        }

        public void logError(String msg) {
            log.error(msg);
        }
    });
}

private void checkRefererUrl() {
    if(GA_REFERER_URL != null) {
        /*
         * If we have a referer URL we need to set this. However, the
         * tracker does not have a getter for the URL binding strategy, so
         * we'll simply create a new one, ugly, but works.
         */
        log.info("Modifying GA tracking to use referer URL: " + GA_REFERER_URL);
        GoogleAnalytics_v1_URLBuildingStrategy urlb;
        urlb = new GoogleAnalytics_v1_URLBuildingStrategy("nexus", "read", GA_TRACKER_ID);
        urlb.setRefererURL("http://m2.cubeia.com");
        // set new referer
        tracker.setUrlBuildingStrategy(urlb);
    }
}

Not too complicated eh? The only thing to note is that the only way to set the refer URL is by creating a new URL building strategy. Well, I can live with that.

Before we go on we’ll create a small subclass on FocusPoint which we’ll use for tracking. Since JGoogleAnalitycs is made primarily for applications the focus point will URL encode itself, however, that won’t work for us, so we need to override it’s getContentURI method:

/**
 * Simple inner class that adapts the content URI to
 * not be URL-escaped.
 */
private static class Point extends FocusPoint {

    public Point(String name) {
        super(name);
    } 

    @Override
    public String getContentURI() {
        return getName();
    }
}

And finally we’ll tie it all toghether. We’ll react on “read” actions, create a URI (of form ‘//path’) and track asynchronously (which will spawn a new thread for calling GA:

public boolean process(Repository rep, ResourceStoreRequest req, Action action) {
    if(action == Action.read) {
        /*
         * 1) create path by appending repo path to repo id
         * 2) create a subclass of focus point that handles proper URI's
         * 3) track asynchronously, this will perform the tracking on a new thread
         */
        String path = rep.getId() + req.getRequestPath();
        log.debug("Tracking path: " + path);
        FocusPoint p = new Point(path);
        tracker.trackAsynchronously(p);
    } else {
        log.debug("Ingoring action '" + action + "' for: " + req.getRequestPath());
    }    
    return true;
}

And that’s it. It’s not perfect: though ideally I’d like to track hosted repositories only, I’d like to avoid tracking crawlers and I would prefer not to configure via system properties (hint for you Nexus bundle users out there, you can set system properties in the “conf/wrapper.conf” files), but I’ll leave those for a rainy day.

Here’s the source code as a Maven project.Enjoy!

Update: If you download and try to compile, you will probably be missing the JGoogleAnalytics lib. You’re welcome to use our, GA-tracked, repository if you like :-)

<repository>
  <id>cubeia-nexus</id>
  <url>http://m2.cubeia.com/nexus/content/groups/public/</url>
  <releases><enabled>true</enabled></releases>
  <snapshots><enabled>true</enabled></snapshots>
</repository>

Write a multiplayer game in 10 minutes or less!

Note: this post is cross-posted on Cubeia.com.

As I was surfing along the other day it struck me that one of the coolest things about Firebase Community Edition is how incredibly fast you can get going. Do you think the title is a boast? Well, in a manner of speaking it is,  you see: we’re using Maven to build, and if you haven’t used Maven to build a Flex/Flash client before, Maven is going to start with downloading half of the Internet for you, and that will inevitably slow you down and may take a few minutes. But hear me! If you have used Maven before, and if you allow for the first time Maven will download the artifacts needed to compile the Firebase game and the Flex client, then I stand firm: you will have a Flex client and a Java server going in less than 10 minutes!Do you want to get started on a multiplayer game really, really fast? Here’s two different ways:

  • The Extreme Quick Start – This hard-core, and Maven only, quick start will have you up in less than 5 minutes (excluding Maven download times). It does not however, send actual game actions between the client and the server, all you can do is join/leave tables and chat with other players… Excuse me? All you can do?! It’s completely awesome if you ask me.
  • The Beloved Hello World – This tutorial can be done with Maven and optionally Flexbuilder. It will explain along the way what happens, and it will also replace the Firebase standard chat with game actions (also chat) showing you how to communicate properly between game server and client. 10 minutes? Well, if you’re impatient and a fast reader, or if you do it twice you will most certainly beat the 10 minute mark.

If you ask me, and I’m obviously biased, this is extremely cool. Of course, this isn’t actually a game yet and there’s a lot more to learn before launching your own international success on Firebase, but hell, you want to write a game? Hop right to it!Update: The commenting system seems to be behaving badly.  Even I can’t seem to comment at the moment. Please check the main blog for updates. I’ll be looking at switching blog system now…

Return top