The unnamed hoppy lager

For a while now, Paul and I have been honing our recipe for our dry hopped lager – that is still without a name – by adding and removing ingredients, and tweaking the quantities and we seems to have hit on something that ticks two main boxes.

1. It’s easy to make.
2. It tastes bloody good.

Now we’re both craft beer lovers and have a strong foundation of beer appreciation kicked along by the fine folks at Emerson’s Brewery and their most excellent Pilsner and Bookbinder recipes. From there we developed a taste for hops (a taste that is not immediately palatable to newcomers) and sought stronger and tastier hop recipes. I don’t know about Paul but I can certainly say there are some beers out there that maybe have too much hops in them – Bridgeport’s “Hop Czar” springs to mind.

Anyway, back to the home brew – here’s our recipe that we’ve developed and you’re welcome to try it yourself and report the results.

Ingredients:

  1. One Cooper’s Lager Home Brew Kit – you can get these from Countdown for about $13 a can.
  2. One 1.5kg tin of Maltexo Malt – we find this at Pak’n'Save in Dunedin for about $8.50 a can.
  3. One sachet of S26 lager yeast – we get this from the Dunedin Malthouse – a home brew store for about $7.
  4. 100 grams of aromatic hops for dry hopping.
We’re not driven by price but when all is said and done we’re making this beer for just over a dollar per 500ml bottle, excluding labour. If you want to make good beer don’t cut corners to get cost down.

The method: First, clean your stuff then clean it again – don’t skimp on this step or you’ll make shit beer. Make the beer as per the instructions in the home brew kit, discarding the yeast that comes with the Cooper’s kit. Put it in your fermenter for one week. We’ve done this recipe so much now that we don’t even bother measureing the OG (original gravity) or FG (final gravity).

After one week, add the dry hops into the barrel in a mesh bag so the flavour can get out but the hops stays in. Weight the bag down with a teaspoon or other heavy object. Don’t forget to sterilise your bag before you put it into your fermenter! As for the hops, we use 100g of hops and generally mix amounts of Riwaka, Motueka or Nelson Sauvin hops. We’ve found a pretty good result with 50/50 Nelson Sauvin and Riwaka but it’s interesting to mix it up a little, especially when you are doing two brews at once.

Then after another week – that’s a week to ferment and a week for dry hopping – we bottle. We use glass bottles from Emerson’s (they give them away to home brewers) with a bit of white sugar to prime the bottles (just because that’s where we’re at). We use a bottle filling wand to make sure there’s as little oxygen as practical getting into the bottles and then cap them with crown caps and a bottle capper. After as little as a week they’re good for tasting (if you’re desperate) but best results kick in after about a month.

The beer that we’re brewing smells very fruity and is big on hops. Many recipes where you dry hop call for about 40g hops so ramping it up to 100g is just bigger. Watch the temperature you ferment at – we had a runaway brew that fermented at very high temperatures ( > 25 dec C ) and it ended up tasting like a whiteboard marker. Seriously it did! We’re aiming to ferment between 11 and 15 degrees C but haven’t got the gear to measure or regulate that properly yet.

Our most recent addition to the equipment lineup is an old vertical freezer with no shelving and no motor. We haven’t tried it yet but it looks like on it’s side it should be able to fit four 23L fermenters in it and keep it at a good temperature.

And a final note – give youself plenty of space – I used to brew in my shed, wedged between my scooter and pile of garden equipment but have since vacated to Paul’s garage where there’s room for a BBQ, a few seats and a gas heater. It’s the ultimate man cave. But yes do watch your setup and make sure there’s space for you to work in – you’ll get the gist of it after a few goes.

Happy brewing!

Content Encoding Error – why?

I was doing some work on an eCeommerce system (OpenCart actually) and then all of a sudden I came across an error in my browser. As it was unexpected and I didn’t know where it came from I checked other browsers and found they were affected also.

The messages I got in the browsers were:

  • Firefox: Content Encoding Error
  • Chrome: net::ERR_CONTENT_DECODING_FAILED
  • Internet Explorer: Internet Explorer cannot display the webpage

Although strangely when I used curl to check that the URL was accessible I got a stream of content displayed in my terminal.

The reason for this is that the browsers specify what content encoding they support when they send the web request, e.g. they can say to the web server “I support compressed responses!” and the server will then oblige with a compressed response (see this article on Wikipedia for full info).

I had accidentally inserted some white space at the start of one of my PHP classes – no errors, no warnings, no nothing – it could have been a real problem to track down.

Here’s some images of the problem in action, along with a screenshot of my terminal with the offending white space visible at the start of line one.

Suspend laptop when lid is closed and power is removed

I changed my power settings on Ubuntu (although that is probably irrelevant for this topic) to sleep when the lid is closed when on battery but not to sleep when the lid is closed and the laptop is powered by AC.

Then, with the laptop on AC and the lid closed (i.e. running normally) I unplugged the AC and put the laptop into my laptop bag and went off to do some things in town.

An hour later I pulled my laptop out of the bag and the hot plastic smell was alarming – fortunately the laptop appears to be OK but this isn’t an episode I want to repeat. I figured that since Linux is quite configurable and is often driven by scripts that are run when certain events occur this issue should be preventable.

While I didn’t find a direct solution via Google I did know enough to eventually find what I wanted. I present this solution as a result. This method appears to work for Ubuntu 12.04 – it may work on other things as well. I didn’t have to install anything in particular to make this work but it does use the pm-utils (power management utils) stuff which may or may not be part of your distribution:

Also I’m not sure how robust the method of determining the lid state is (e.g. what if you have a LID0 and a LID1????). Someone said they wanted to see my laptop if it had a LID0 and a LID1 :)

Anyway, I created a file here : /usr/lib/pm-utils/power.d/suspend-when-ac-removed-while-lid-closed and made sure it was executable (i.e. chmod a+x /usr/lib/pm-utils/power.d/suspend-when-ac-removed-while-lid-closed)

Now for the script:

#!/bin/sh
 
. "${PM_FUNCTIONS}"
 
suspend() {
    # Check lidstate - open = 1, closed = 0
    LIDSTATE=`cat /proc/acpi/button/lid/LID0/state|grep open|wc -l`
    case "$LIDSTATE" in
        0) pm-suspend ;;
        *) echo Unknown $LIDSTATE ;;
    esac
}
 
case $1 in
    true) suspend ;;
    false) exit $NA ;;
    *) exit $NA ;;
esac
 
exit 0

I didn’t need to restart pm-utils or any services, this just started working when I dropped the file in. To test:

  1. Configure Ubuntu to not suspend when you shut the lid and there is AC power.
  2. Shut the lid of your laptop (it should remain on).
  3. Remove the AC.
  4. The laptop should suspend.
  5. Open the lid and unlock the screen.
  6. Remove the execute flag (effectively disabling the script), chmod a-x /usr/lib/pm-utils/power.d/suspend-when-ac-removed-while-lid-closed
  7. Shut the lid and remove AC.
  8. The laptop should stay on.

In my testing over the last few days this appears to work all of the time – still after the heating episode I do check each time to see that it does sleep.

Dunedin area code to location list

When you know an area well you get to know the area code for local suburbs – e.g. Mosgiel people know that all other Mosgiel people (and some close neighbours) are “489″. I figured it shouldn’t be too hard to collect that data from online services and then do some analysis on it. Armed with PHP and jQuery (which I must commend for being super accommodating through this process) I present you with the results.

--------------------------------------------------------------------------
DUNEDIN PHONE NUMBER TO AREA LIST
--------------------------------------------------------------------------
  This list is based on a subset of 2,795 phone numbers
  Generated Mon, 23 Apr 2012 00:44:03 +1200 from public phone number lists.
  Compiled by bob@guru.net.nz, www.guru.net.nz.
  This list contains 28 phone suffixes and 96 distinct areas.

  Note: The % in the list is how many numbers in that area code are in the
  listed suburb (e.g. if 03-453 says Mornington 44% and Belleknowes 21% then
  that means that 44% of the 03-453 area numbers are Mornington based and 21%
  are Belleknowes based)

Read more »

Setting up an Ubuntu 10.10 laptop for LAMP development

I’m blogging this mostly for my reference as I occasionally reinstall my laptop and always forget the steps to get back to a good state.

Aim:

  • Ubuntu Linux 10.10 desktop
  • Apache 2.2
  • MySQL 5.1
  • PHP 5.2

Firstly, install Ubuntu 10.10. Make sure you opt to encrypt your home directory. While this means it’s difficult to recover contents of your home directory in the event of an OS crash, it’s also means you can sleep at night knowing that if you lose your laptop you haven’t lost your intellectual property. The system overhead for doing this is not really noticable. The down side of this is that you cannot access the files unless you’re logged on (see the bit later about the projects directory and Apache).

Now, let’s install Apache, MySQL and PHP. Note that I’m installing some extra packages that I need for my development purposes.

bob@bob-laptop:~$ sudo apt-get install libapache2-mod-php5 mysql-server php5-mysql
bob@bob-laptop:~$ sudo apt-get install php5-curl php-pear  # some extras I use
bob@bob-laptop:~$ sudo apt-get install openssh-server subversion bzr  # some extras I use

During the installation of those packages you’ll be asked for a password for the MySQL root user. I always use “root” for my convenience. You can use whatever you like. This user does not have root access to the system, but will have full access to the MySQL databases. By default MySQL only listens on the localhost interface so an insecure password like “root” is acceptable for my purposes. You’ll see later that we can shift certain databases to reside on the encrypted home directory if that’s important to you.

Set up the projects directory

I like to keep all my web stuff in a subdirectory of my home directory called projects. The full path to that will be /home/bob/projects. In order to be able to browse these projects with Apache I’ll put a symlink in /var/www (Apache’s default web root directory) to it.

Here’s a terminal session where I create the projects directory.

bob@bob-laptop:~$ mkdir ~/projects
bob@bob-laptop:~$ sudo ln -s ~/projects /var/www/projects
bob@bob-laptop:~$ ls -l /var/www
total 4
-rw-r--r-- 1 root root 177 2011-12-11 15:30 index.html
lrwxrwxrwx 1 root root  18 2011-12-12 21:25 projects -> /home/bob/projects

Great. But now if you try to access http://localhost/projects you’ll get a 403 Forbidden page. This is because Apache isn’t able to see your home directory. A small tweak will fix that.

bob@bob-laptop:~$ chmod o+x ~

Note that this command will allow any other user (of which Apache’s www-data is one) on your system to see the files in your home directory. For me this isn’t an issue as I’m the only user on my system.

Now if you revisit http://localhost/projects you’ll get a directory index instead of a 403 Forbidden page. You can now create files in /home/bob/projects (or whatever your user name is) and Apache will be able to serve them up to your web browser.

Note that because we opted to encrypt the home directory, the /home/bob directory is only mounted when bob logs in. This means that if you boot your system and try to access it over the network without being logged in, you’ll likely get a 403 Forbidden or 404 Page Not Found error for any URL in /projects. Other files can be placed in /var/www/whateveryoulike and will be accessible regardless.

Example:

bob@bob-laptop:~/projects$ cat > phpinfo.php
<?php phpinfo(); ?>

(press Ctrl-D after typing the phpinfo() line to save the file)

Now if you browse to http://localhost/projects/phpinfo.php you will get the standard PHP Information page.

Using an encrypted database

We’re not so much using an encrypted database as we are moving it onto an encrypted file system. We use the same trick that we used for Apache but we’re doing this for MySQL. Note that while it is possible to have all databases encrypted, you will need to make sure you log on first before you start MySQL. Here I will just encrypt one database:

-- Create a mysql directory in my home dir.
bob@bob-laptop:~$ mkdir ~/mysql

-- Create a sample mysql database called 'secure'
bob@bob-laptop:~$ mysqladmin -uroot -proot create secure

-- Stop the mysql service
bob@bob-laptop:~$ sudo stop mysql
mysql stop/waiting

-- Move the newly created 'secure' database to my home dir
bob@bob-laptop:~$ sudo mv /var/lib/mysql/secure ~/mysql

-- Create a symbolic link for mysql to use
bob@bob-laptop:~$ sudo ln -s ~/mysql/secure /var/lib/mysql/secure

-- Start mysql again
bob@bob-laptop:~$ sudo start mysql
mysql start/running, process 2778

-- Now access the database in the new place
bob@bob-laptop:~$ mysql -uroot -proot
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 34
Server version: 5.1.49-1ubuntu8.1 (Ubuntu)

Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
This software comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to modify and redistribute it under the GPL v2 license

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> use secure;
Database changed

No errors – the connection was successful. Again the same thing applies in that you can only access this database while you are logged on.

.htaccess files (optional, but recommended)
Out of the box, Apache won’t read .htaccess files. To enable these permanently for all directories under your /var/www directory (including the project directory), edit the /etc/apache2/sites-enabled/000-default file (as root) and change line 11 to say “AllowOverride All” (instead of None).

mod_rewrite (optional, but recommended)

Also, you may want to enable mod_rewrite as many web applications use this to generate nice looking URL’s.

bob@bob-laptop:~$ sudo a2enmod rewrite
bob@bob-laptop:~$ sudo apache2ctl restart

xdebug plugin for PHP

The xdebug plugin gives you nice stack traces and formatted var_dump()s which makes it easier to develop. It also comes with breakpoints, remote debugging and a range of other things. Check out the whole shebang at http://xdebug.org/.

Installation is simple:

bob@bob-laptop:~$ sudo apt-get install php5-xdebug

Restart Apache for the change to take effect (sudo apache2ctl restart).

Enabling display of errors in your browser

By default PHP ships with display_errors = Off. This is a requirement for a production system but it will drive you nuts on a development box. When off, any errors are logged to Apache’s error_log file in /var/log/apache.

To turn it on, edit the file /etc/php5/apache2/php.ini and look for the lines like this:

display_errors = Off
display_startup_errors = Off
html_errors = Off

And change them all to “On”. Again, restart Apache for the change to take effect (sudo apache2ctl restart).

Happy developing!

Consistency

Warning: this may be the most valuable blog post you ever read.

I’ve been developing for a long time – the first programs that I first wrote that other people were using was back in 1992. At the time, I was the only one working on the code and there was no reason for others to get involved. In fact back then it seemed that we were driven by one-upmanship and sharing code was almost unheard of, unless you had to get an assignment in the next day and you had some stupid reason for not being able to complete it, then someone might take pity on your ass and bail you out. Back then, consistency wasn’t important – what mattered was whether the code ran or not. Even better if it ran and you got paid.

If there’s one thing I could share with you about my experiences over the last twenty years, I would have to say that it’s this. Be consistent.

Consider the following code:

<?php
  $query = 'select * from customer where id = 123';
  $result = mysql_query($query);
  $row = mysql_fetch_assoc($result);
  $identifier = $row['id'];
  echo $identifier;
?>

We’re fetching a row from a table and echoing out the id field. The code above doesn’t really matter, but what does matter is the inconsistency. Can you spot it?

The inconsistency is that the field in the database is called “id” and we put it into a variable called $identifier. This does not break the code, but it does mean that you have just introduced an inconsistency that will bite you.

That’s a pretty simple example, but imagine those kind of differences across an entire application, a database schema or even your whole organisation. It happens, and all too frequently.

The consistency issue isn’t a coding style issue – let me be very clear on that – it’s more a culture issue. You need to work hard to spot these inconsistencies in your organisation and nip them in the bud really early. And they may not appear in code either. You can find them anywhere from code, to documentation, to common usage in discussions in the workplace.

If you let these inconsistencies propagate you’re going to have to deal with them time and time again. Here’s a real world example: I am dealing with a system at the moment where products are identified by their SKU number (Stock Keeping Unit). This number has been referred to as the following in various places (code, documentation, wiki pages, emails etc):

  • ItemCode
  • ItemId
  • Item_Id
  • ItemID (yes, case makes a difference!)
  • ItemSKU
  • Identifier
  • Identifer (yes, misspelling of Identifier)
  • ProductId
  • ProductSku
  • SKU

The boat has sailed on that one – there is no way that this situation could be wrestled under control, you’ll have to do what you can if you come across this. But if you have the luxury of a fresh project then it’s time to gather your troops and spell it out on the board – CONSISTENCY. Drum it into your processes and procedures, your code reviews and commit messages. There’s no excuse for any inconsistency at all – especially when it will cost you in time chasing bugs because the value isn’t turning up like it should or the record isn’t saving.

If you haven’t already I highly recommend putting together some coding standards for your company – or even for yourself. And follow them to the letter. It doesn’t really matter what style of indenting you use (K&R, Allman, BSD KNF, Whitesmiths etc) – what matters is that you’re … you know what I’m going to say don’t you.

Feel free to borrow from the Turboweb Coding Standards (which in turn were based on the Drupal Coding Standards). Make sure that your new starts read your coding standards and understand them. And take time to teach them well.

Addendum: Ironically I managed to misspell the title of this blog post, I’ve now corrected it but as the link is out and about on various social media sites I can’t change that, therefore if you’re viewing this post by itself you’ll see that the URL says “consitency” :)

WordPress Themes