How to connect a USB receipt printer up on Mac OS X

This post will show you how to set up a USB receipt printer on Max OS X. These steps were written on Yosemite, but should work on 10.6 onwards (ie, also Snow Leopard through to El Capitan).

This is another post in a series, which has so far covered direct USB printing on Windows and Linux. The printer tested here is this Epson TM-T20:


CUPS is the printing system that’s used on Mac, but most users would be more familiar with the system print dialog:


In our case, we need to set up the printer via the CUPS web interface. This is accessed via a web browser at this address:


At first, you will get knocked back:


To fix this up, open up Applications → Utilities → Terminal and type in:

cupsctl WebInterface=yes

You can then reload the browser and click through to Administration:


Click Add Printer and log in:



Select the USB printer from the list, and optionally share it:



Click Select Another Make/Manufacturer, and select Raw → Raw Queue:




Use the defaults for the other options:


Test print

Type some junk into a file called foo.txt and attempt to print it, using the CUPS printer name:

nano foo.txt
lpr -o raw -H localhost -P EPSON_TM-T20 foo.txt

The prints will be delayed for a few moments, as CUPS spools the jobs.

Disable CUPS web

Once you’re done, for security reasons you should reset this option from before, to disable the web interface to CUPS:

cupsctl WebInterface=no

How to set up sudo on Debian GNU/Linux

If you just installed Debian, you might notice that one Linux staple, sudo is not installed by default. Here is the quick way to add it, and set yourself up as an administrative user.

1. Install sudo, using the su command to elevate privileges.

bob$ su
root# apt-get install sudo

2. Make yourself an administrator. The default /etc/sudoers file contains this line:

# Allow members of group sudo to execute any command

So simply add your account (‘bob‘ in this example) to the sudo group:

root# usermod -a -G sudo bob

3. Log out and back in again, in order to apply changes to your group membership.

bob$ groups
bob cdrom floppy sudo audio dip video plugdev netdev lpadmin scanner bluetooth
bob$ sudo echo test
[sudo] password for bob: 

Fix merge conflicts in git with Meld

When you’re writing code collaboratively, there’s plenty of situations when you need to combine two sets of changes.

This could happen, for example, if Bob and yourself both fix different bugs by making edits to the same file.


This post assumes that your source code is tracked in git.

First up, install meld. The Meld homepage has instructions for other platforms, but on Debian/Ubuntu, it’s just:

sudo apt-get install meld

Now tell git to use it as a tool:

git config --global merge.tool meld

Once you have a merge conflict, you can then fire up Meld like this:

git mergetool

For each file, you will get a 3-way diff. Click the arrows on the sides to move the code you want into the middle:


Once you’ve saved the file and closed Meld, you will be prompted on the command-line. You just tell it whether you’ve successfully merged the file, until it stops giving you new files to merge.

After this, commit the changes:

git commit


Simpler usage

If you don’t use git, you can simply call Meld from the command-line as well. This shows you differences between files in a similar window, and lets you move blocks of code around as well:

meld foo.c bar.c

Continuous testing in PHP with Eclipse

If you already write test cases over your code, then continuous testing is a simple idea: Get fast feedback on your code by running your project’s unit tests very frequently. From PHP, the de facto standard testing tool is PHPUnit, so running tests usually involves typing phpunit into a terminal.

This post will show you how to set up a project with the Eclipse MakeGood plugin, which is a continuous test runner for the Eclipse IDE. When it is enabled, the plugin runs a set of tests every time you save a file.

This is best used on projects which are:

  • Small — so you tests run in a reasonable timeframe.
  • Complex — reasonably high risk of introducing defects.
  • Well-tested — so your unit tests are reasonably likely to identify defects.

Set up your machine

Your machine needs Eclipse PDT, MakeGood and composer.

Eclipse PDT

If you’ve found this post via Google, then you probably already run Eclipse and PHP. If not, fetch the “Eclipse for PHP developers” distribution from here

You need to pick up the XDebug extension to really make use of this setup. On Debian-based distributions, this is achieved via:

sudo apt-get install php5-xdebug

If you don’t use Eclipse yet, then check whether languages or tools you’ve used before have plugins in the Eclipse Marketplace. There’s a good chance that Eclipse will do the whole lot.


MakeGood is simply an Eclipse plugin, so you can fetch it from the Eclipse Marketplace.

Navigate to Help → Eclipse Marketplace and search for “makegood”:


Wait for the info to be fetched:

Check all the boxes, and then click Confirm:


Accept the terms, and wait for the install:


At one point, you will be prompted to accept a developer’s certificate, which you need to do before continuing:


This feature will not work unless you have a PHP binary set up. You need to configure this under Window → Preferences → PHP → PHP executables.:


This is system dependent: Windows users will find a file somewhere called php-cli.exe, while Linux users might find it at /usr/bin/php.

After this, MakeGood is installed. It is configured per-project, so we’ll get to that after the next section.


Composer is a dependency manager which is widely used in the PHP world.

You can get it from

Rather than use the install process which is suggested there, you can simply download the phar, make it executable, and place it somewhere like /usr/bin:

chmod +x composer.phar
sudo mv composer.phar /usr/bin/composer
composer --version

By using composer to load PHPUnit, MakeGood becomes much easier to configure.

Project setup

To start, make a new PHP project by clicking File → New → PHP Project. Name it something like “Example”.

We are using composer here because it provides an easy way to make sure MakeGood can see the PHPUnit code. So let’s set a few things up:

First, add a composer.json file which adds a recent version of PHPUnit as a require-dev dependency. Right-click Example project, and navigate to New → File, naming it composer.json:

    "require-dev": {
        "phpunit/phpunit": "4.5.*"

Note that with the way that MakeGood constructs its command-line, newer versions of PHPUnit do not appear to work correctly at the time of writing.

Next up, install the new dependency with the help of Composer:

$ composer install
Loading composer repositories with package information
Installing dependencies (including require-dev)
  - Installing sebastian/version (1.0.6)
  - Installing sebastian/global-state (1.0.0)
  - Installing sebastian/recursion-context (1.0.1)
  - Installing sebastian/exporter (1.2.1)
  - Installing sebastian/environment (1.3.2)
  - Installing sebastian/diff (1.3.0)
  - Installing sebastian/comparator (1.2.0)
  - Installing symfony/yaml (v2.7.3)
  - Installing doctrine/instantiator (1.0.5)
  - Installing phpdocumentor/reflection-docblock (2.0.4)
  - Installing phpspec/prophecy (v1.4.1)
  - Installing phpunit/php-text-template (1.2.1)
  - Installing phpunit/phpunit-mock-objects (2.3.6)
  - Installing phpunit/php-timer (1.0.7)
  - Installing phpunit/php-token-stream (1.4.3)
  - Installing phpunit/php-file-iterator (1.3.4)
  - Installing phpunit/php-code-coverage (2.2.2)
  - Installing phpunit/phpunit (4.5.1)

sebastian/global-state suggests installing ext-uopz (*)
phpdocumentor/reflection-docblock suggests installing dflydev/markdown (~1.0)
phpdocumentor/reflection-docblock suggests installing erusev/parsedown (~1.0)
phpunit/phpunit suggests installing phpunit/php-invoker (~1.1)
Writing lock file
Generating autoload files

Set up an Example.php class with a bit of code:

 * Example of some code that could do with test cases
class Example {
	 * Faulty palindrome checker. A palindrome is a word which is the same when read orward and backward.
	 * @param string $str
	 * @return boolean True if $str is a palindrome, false if it is not.
	function isPalindrone($str) {
		$halfLen = (int)(strlen($str) / 2);
		for($i = 0; $i < $halfLen; $i++) {
			// Compare characters from the front and back of the string, and move toward the middle.
			$c1 = substr($str, $i, 1);
			$c2 = substr($str, (2 * $halfLen - 1) - $i, 1);
			if($c1 != $c2) {
				return false;
		return true;


Set up a test/unit folder and create a ExampleTest class with a useful test case in it, like so:

class ExampleTest extends PHPUnit_Framework_TestCase {
	public function testIsPalindrome() {
		$e = new Example();
		$this -> assertTrue($e -> isPalindrone(""));
		$this -> assertTrue($e -> isPalindrone("a"));
		$this -> assertTrue($e -> isPalindrone("ABBA"));
		$this -> assertFalse($e -> isPalindrone("test"));

The unit tests go in their own folder, in case you decide to add more extensive (slower) tests later. MakeGood should only be configured to run fast tests!

Now add a test/bootstrap.php for test cases to load classes (NB: At scale, you would have composer autoload your classes, and use that as your PHPUnit class loader).

require_once 'vendor/autoload.php';
require_once 'Example.php';

Optionally, also add a phpunit.xml file in your project root to configure PHPUnit with, so that you can run it on the command-line:


If all goes to plan, your project should look something like this:

- Continuous testing example
  |- (.. code ..)
  |- Example.php
  |- test/
  |  |- (.. other types of tests ..) 
  |  |- unit/
  |  | |- ExampleTest.php
  |  |- bootstrap.php
  |- vendor
  |  |- (.. dependencies ..)
  |  |- autoload.php
  |- composer.json
  |- phpunit.xml

And more to the point, you should be able to use PHPUnit on the command-line to run the test case. It will look something like this:

Example$ php vendor/bin/phpunit test/unit/
PHPUnit 4.7.7 by Sebastian Bergmann and contributors.


Time: 71 ms, Memory: 4.50Mb

OK (1 test, 4 assertions)

Configure MakeGood

Now that the project is coming along nicely, it’s time to configure MakeGood to run the test automatically from within Eclipse.

Go to Project → Properties → MakeGood, and add the path to your unit tests, along with a link to the bootstrap.php. This bootstrap file will let MakeGood load the classes to test, along with PHPUnit itself.


Now fire up the MakeGood view. If it doesn’t come up automatically, then open it via Window → Show View → Other. Clicking the “play” button should kick off all available tests, adn if your project structure is correct, then everything will work at this point:


Once you save a file, a small box will appear in the bottom-right to indicate whether the tests worked.


As you introduce changes and save them, MakeGood will flag whether the tests are passing by changing the colour of the icon.

In this case, it is green. From the small delay that is caused when running the tests, you can see why it’s important to keep unit tests fast if you use this tool.

A test-driven bugfix cycle

Of course, Linus’ Law suggests that any code will probably have more bugs. So, say somebody reports that the palindrome “abcdedcba” is causing incorrect results. In test-driven development, you would expose this as a test case over the isPalindrome() function:

	public function testIsPalindromeOddLength() {
		$e = new Example();
		$this -> assertTrue($e -> isPalindrone("abcdedcba"));
		$this -> assertFalse($e -> isPalindrone("abc"));

As soon as this is submitted, things start to turn red in MakeGood. In response to the broken test, you can then tweak the code.


You would then do the smallest amount of programming needed to pass all the tests. A palindrome checker which does not contain intentional bugs is as simple as this one-liner:

	function isPalindrone($str) {
		return $str == strrev($str);

This change causes MakeGood to report that the unit tests are all passing.



A continuous test runner adds faster feedback for tedious but well-tested code. If you have to write anything in PHP which does some real computer work, then I suggest setting up MakeGood so that you can make changes to tricky code, and have a good idea of whether it’s producing sane outputs.

As this post has touched on before, slow tests should not run each time you save the code. This is why we worked in a Unit test folder. Slower integration or functional tests can still be run via the command-line in this model. An example of a project which uses this setup is escpos-php, which is a heavily test-driven PHP driver for thermal line printers.

It’s time to migrate away from Outlook Express

Outlook Express is obsolete, so you need to migrate if you’re still using it. This post is a quick guide to saving your local data so that you can jump ship.

If you are keen on desktop-based email, then there are only two real contenders for a replacement mail client:

  • Mozilla Thunderbird (suggested).
  • Windows Mail.

So where is all my data?

The script below is a Windows bat script for backing up an Outlook Express setup. Just fill in the Identity variable and run it from anywhere to produce a folder containing the Outlook saved emails and contacts.

You can find your identity string as a folder name in your profile path, under Local Settings\Application Data\Identities\. The profile path for a user called bob would usually be in a folder like C:\Documents and Settings\bob or C:\Users\bob.

These files can be read by both of the suggested replacements, so a good transition might be:

  1. Make a backup.
  2. Install an alternative & set it up.
  3. Try to import as much as you can.
  4. Once you’re happy, uninstall Outlook Express, or at least delete the shortcuts to it.
@echo off
ECHO -------------------------------------------------------------------------------
SET BACKUPDIR="%username% - Outlook Backup"
ECHO Backing up outlook files to: %backupdir%
ECHO --------------------------------------------------------------------------------

ECHO - Clearing backup location... (1 of 3) 
DEL /F /S /Q %backupdir% > NUL 2>&1
MKDIR %backupdir% 2> NUL
ECHO - - Done

ECHO - Copying emails... (2 of 3) 
MKDIR %backupdir%\Emails 2> NUL
XCOPY /E /H /C /R /Y "%userprofile%\Local Settings\Application Data\Identities\%IDENTITY%\Microsoft\Outlook Express" %backupdir%\Emails > NUL
ECHO - - Done

ECHO - Copying address book... (3 of 3)
MKDIR %backupdir%\AddressBook 2> NUL
XCOPY /E /H /C /R /Y "%appdata%\Microsoft\Address Book" %backupdir%\AddressBook > NUL
ECHO - - Done

ECHO - Completed 3 of 3 tasks.
ECHO -------------------------------------------------------------------------------
ECHO The backup is complete.
ECHO Please copy %BACKUPDIR% to external storage.
ECHO --------------------------------------------------------------------------------

Raspberry Pi KA Lite wireless deployment

Previous post in this series: How to install KA Lite on the Raspberry Pi

If you got to the end of the previous post, you would have a working install of the open source KA Lite system on the Raspberrry Pi.

This post will show you how to deploy this KA Lite setup without relying on any existing network infrastructure:


To share the setup without an existing network, we will configure the wireless adapter to provide its own network for computers to connect to. If you have an existing wireless network, you can skip this post.

Before you begin

This post is intended for the widely-used “WiPi” USB WiFi adapter, so you’ll need one of those.

I used the same Tenda USB WiFi adapter as previous setups, which has a Ralink chip from the same series:

USB WiFi Adapter

Set it up

See the official guide for these steps in compact form. These steps are the same, but expanded with extra output from my install.

Clone the raspberry pi scripts repo:

$ git clone
Cloning into 'ka-lite-pi-scripts'...
remote: Counting objects: 66, done.
remote: Total 66 (delta 0), reused 0 (delta 0), pack-reused 66
Unpacking objects: 100% (66/66), done.

Open it up and run ./ as the root user. This requires Internet access, and will install and configure a few packages:

$ cd ka-lite-pi-scripts/
$ ls
$ sudo ./
Get:1 wheezy Release.gpg [490 B] 
Hit wheezy Release.gpg                        
Hit wheezy Release.gpg
Get:2 wheezy Release [14.4 kB]
Hit wheezy Release                      
Hit wheezy Release                        
Hit wheezy/rpi armhf Packages           
Get:3 wheezy/main armhf Packages [129 kB]       
Get:4 wheezy/main armhf Packages [6903 kB]  
Ign wheezy/rpi Translation-en                 
Ign wheezy/main Translation-en                
Get:5 wheezy/contrib armhf Packages [23.6 kB]
Get:6 wheezy/non-free armhf Packages [49.3 kB]
Get:7 wheezy/rpi armhf Packages [592 B]     
Ign wheezy/contrib Translation-en           
Ign wheezy/main Translation-en              
Ign wheezy/non-free Translation-en          
Ign wheezy/rpi Translation-en
Fetched 6992 kB in 35s (198 kB/s)             
Reading package lists... Done
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following packages will be upgraded:
  cups-bsd cups-client cups-common fuse libcups2 libcupsimage2 libfuse2 raspi-config
8 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
Need to get 1708 kB of archives.
After this operation, 306 kB disk space will be freed.
Get:1 wheezy/main raspi-config all 20150131-4 [13.2 kB]
Get:2 wheezy/main libcupsimage2 armhf 1.5.3-5+deb7u6 [132 kB]
Get:3 wheezy/main cups-common all 1.5.3-5+deb7u6 [904 kB]
Get:4 wheezy/main cups-bsd armhf 1.5.3-5+deb7u6 [44.2 kB]
Get:5 wheezy/main cups-client armhf 1.5.3-5+deb7u6 [174 kB]
Get:6 wheezy/main libcups2 armhf 1.5.3-5+deb7u6 [238 kB]
Get:7 wheezy/main fuse armhf 2.9.0-2+deb7u2 [70.8 kB]
Get:8 wheezy/main libfuse2 armhf 2.9.0-2+deb7u2 [132 kB]
Fetched 1708 kB in 3s (447 kB/s)
Preconfiguring packages ...
(Reading database ... 83674 files and directories currently installed.)
Preparing to replace libcupsimage2:armhf 1.5.3-5+deb7u5 (using .../libcupsimage2_1.5.3-5+deb7u6_armhf.deb) ...
Unpacking replacement libcupsimage2:armhf ...
Preparing to replace cups-common 1.5.3-5+deb7u5 (using .../cups-common_1.5.3-5+deb7u6_all.deb) ...
Unpacking replacement cups-common ...
Preparing to replace cups-bsd 1.5.3-5+deb7u5 (using .../cups-bsd_1.5.3-5+deb7u6_armhf.deb) ...
locale: Cannot set LC_ALL to default locale: No such file or directory
Unpacking replacement cups-bsd ...
Preparing to replace cups-client 1.5.3-5+deb7u5 (using .../cups-client_1.5.3-5+deb7u6_armhf.deb) ...
Unpacking replacement cups-client ...
Preparing to replace libcups2:armhf 1.5.3-5+deb7u5 (using .../libcups2_1.5.3-5+deb7u6_armhf.deb) ...
Unpacking replacement libcups2:armhf ...
Preparing to replace fuse 2.9.0-2+deb7u1 (using .../fuse_2.9.0-2+deb7u2_armhf.deb) ...
Unpacking replacement fuse ...
Preparing to replace libfuse2:armhf 2.9.0-2+deb7u1 (using .../libfuse2_2.9.0-2+deb7u2_armhf.deb) ...
Unpacking replacement libfuse2:armhf ...
Preparing to replace raspi-config 20150131-3 (using .../raspi-config_20150131-4_all.deb) ...
Unpacking replacement raspi-config ...
Processing triggers for man-db ...
Processing triggers for initramfs-tools ...
Setting up libcups2:armhf (1.5.3-5+deb7u6) ...
Setting up libcupsimage2:armhf (1.5.3-5+deb7u6) ...
Setting up cups-common (1.5.3-5+deb7u6) ...
Setting up cups-client (1.5.3-5+deb7u6) ...
Setting up cups-bsd (1.5.3-5+deb7u6) ...
Setting up libfuse2:armhf (2.9.0-2+deb7u2) ...
Setting up fuse (2.9.0-2+deb7u2) ...
udev active, skipping device node creation.
update-initramfs: deferring update (trigger activated)
Setting up raspi-config (20150131-4) ...
update-rc.d: warning: default start runlevel arguments (2 3 4 5) do not match raspi-config Default-Start values (S)
update-rc.d: warning: default stop runlevel arguments (0 1 6) do not match raspi-config Default-Stop values (none)
Processing triggers for initramfs-tools ...
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following extra packages will be installed:
  dnsmasq-base libnetfilter-conntrack3
The following NEW packages will be installed:
  dnsmasq dnsmasq-base hostapd libnetfilter-conntrack3
0 upgraded, 4 newly installed, 0 to remove and 0 not upgraded.
Need to get 822 kB of archives.
After this operation, 1653 kB of additional disk space will be used.
Get:1 wheezy/main libnetfilter-conntrack3 armhf 1.0.1-1 [32.2 kB]
Get:2 wheezy/main dnsmasq-base armhf 2.62-3+deb7u3 [356 kB]
Get:3 wheezy/main dnsmasq all 2.62-3+deb7u3 [16.3 kB]
Get:4 wheezy/main hostapd armhf 1:1.0-3+deb7u2 [418 kB]
Fetched 822 kB in 4s (168 kB/s)  
Selecting previously unselected package libnetfilter-conntrack3:armhf.
(Reading database ... 83674 files and directories currently installed.)
Unpacking libnetfilter-conntrack3:armhf (from .../libnetfilter-conntrack3_1.0.1-1_armhf.deb) ...
Selecting previously unselected package dnsmasq-base.
Unpacking dnsmasq-base (from .../dnsmasq-base_2.62-3+deb7u3_armhf.deb) ...
Selecting previously unselected package dnsmasq.
Unpacking dnsmasq (from .../dnsmasq_2.62-3+deb7u3_all.deb) ...
Selecting previously unselected package hostapd.
Unpacking hostapd (from .../hostapd_1%3a1.0-3+deb7u2_armhf.deb) ...
Processing triggers for man-db ...
Setting up libnetfilter-conntrack3:armhf (1.0.1-1) ...
Setting up dnsmasq-base (2.62-3+deb7u3) ...
Setting up dnsmasq (2.62-3+deb7u3) ...
[ ok ] Starting DNS forwarder and DHCP server: dnsmasq.
Setting up hostapd (1:1.0-3+deb7u2) ...
[ ok ] Starting advanced IEEE 802.11 management: hostapd.
[ ok ] Starting DNS forwarder and DHCP server: dnsmasq[....] (already running).
update-rc.d: using dependency based boot sequencing
update-rc.d: using dependency based boot sequencing

Next, run run the ./ script:

$ ./ 
[ ok ] Stopping advanced IEEE 802.11 management: hostapd.
[ ok ] Starting advanced IEEE 802.11 management: hostapd.

And then the ./ script as root:

sudo python ./

After this ran, the /etc/network/interfaces file looked like:

$ sudo nano /etc/network/interfaces
auto lo
iface lo inet loopback

auto eth0
#allow-hotplug eth0
iface eth0 inet manual

auto wlan0
#allow-hotplug wlan0
wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf

auto wlan1
#allow-hotplug wlan1
iface wlan1 inet manual
wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf

iface wlan0 inet static
  pre-up sudo iptables -t nat -A PREROUTING -i wlan0 -p tcp -j DNAT --to-destination
  pre-up sudo python /home/pi/ka-lite/ka-lite-pi-scripts/ &

And I modified /etc/default/ifplugd to only include eth0, so that the pi does not attempt to join any wireless networks itself:

$ sudo nano /etc/default/ifplugd
ARGS="-q -f -u0 -d10 -w -I"

And then reboot:

$ sudo reboot

Broadcast message from root@raspberrypi (pts/0) (Thu Jun 11 11:05:46 2015):

The system is going down for reboot NOW!

See if its all working

Disregard the old addresses once you’ve done the above steps, and run ifconfig to find out about addresses after rebooting.

The pi broadcasts a passwordless wireless network called “kalite”, and all DNS lookups point to

This means in a web browser, you can just load a URL like:



On a laptop in range, the network appeared once the pi booted:


The network connected without a password:


And the connection info for the client computer is being checked in the background:


Once the computer gets a lease from DHCP, the URL loads, and the interface works as expected:


Tested on Android, the player and navigation worked in a similar way:


KA Lite’s media player doesn’t seem to require anything other than a web browser. Either Chrome or Firefox seem to be suitable choices.

Debug zone

Some useful commands for debugging are shown below.

List USB devices, for debugging the wireless adapter:


List recent errors, for debugging the same thing:


Restart networking, run when changing configuration:

service networking restart
Note on dnsmasq

Because of the way dnsmasq hijacks lookups to provide the wireless network, the Raspberry pi cannot access the Internet over Ethernet (eg, to download content) while dnsmasq is running:

sudo service dnsmasq stop

You can access the web interface at while this service is disabled.

And then start it again when done using the Internet, so that the user-friendly computer name works again:

sudo service dnsmasq start

How to create an animated GIF from a series of images

Sometimes, you end up with a folder full of images, which you want to animate. With the open source ImageMagick tool, this is easy on the command line:

animate *.png

This will show you all of the PNG files in the folder in quick succession, like a flip book.

ImageMagick works on just about any OS. For Linux users, the package is generally imagemagick or ImageMagick:

sudo apt-get install imagemagick
yum install ImageMagick

But this blog post is about animated GIFs, so lets make one of those. This is a compact way to combine images (here and here for examples in context), gives you a re-usable at-a-glance illustration of something that changes over time.

Example from an older post:


The steps to make a good conversion command are:

  1. Check that alphabetically, your images are in order. If not, rename them:
    echo *
  2. Convert them to a GIF a few times, and find the delay that suits you (hundredths of a second between frames)
    convert -delay 80 *.png animated.gif
  3. Choose an output size (width x height):
    convert -resize 415x -delay 80 *.png animated.gif
  4. Compress with -Layers Optimize for a smaller file:
    convert -resize 415x -delay 80 *.png -layers Optimize animated.gif


  • Generated thumbnails usually take the first frame only, which is why we ask Imagemagick to resize it (WordPress users: Choose “Full Size”).
  • To pause at the start of the loop for a moment, just copy the first image a few times.

How to install KA Lite on the Raspberry Pi

KA Lite is an open source, web-based learning package. Today I’ll run through a simple setup which will allow a Raspberry Pi to provide a wireless learning resource server for a classroom, without the Internet.


The Raspberry Pi 2 is a surprisingly powerful single-board computer. You can use it for anything which a computer can do, in a relatively cheap circuit board the size of a credit card:


This setup takes around two hours.


You will need:

  • Raspberry Pi (The Raspberry Pi 2 Model B was used here), with micro SD card, mouse, keyboard, monitor with HDMI.
  • A good Micro USB power supply – Many Android phone chargers will be suitable.
  • A computer which can write to micro SD cards. If your computer has an SD card slot, get an SD-to-Micro-SD adapter for it.
  • A wired network with Internet for the setup
  • A USB wireless network adapter such as WiPi for deployment.
  • Any WiFi-enabled device for testing.

Install Raspbian

Raspbian is an operating system for the Pi, and is the perfect choice for embedded server setups like this. You need to write the image to the Micro SD card.

  1. Obtain the image from
  2. This is zipped, so extract it to get the real image file.
  3. Write the disk image to the SD card:
    • Windows: Fetch a copy of “Win32 Disk Imager” to write this file to the SD card.
    • Linux or Mac: Use dd (found in the terminal) to write to the card — guide available here
  4. Boot the Pi, with mouse, keyboard, HDMI, and wired network. If it doesn’t work, remove any cable converters (use HDMI direct to monitor), and if it still doesn’t work, then the SD card was not correctly imaged.
  5. Expand root filesystem, set your password, and enable “boot to desktop”.
  6. After reboot, you should have a desktop. Click the black terminal icon to get to work.

Install some things

From the terminal, run these commands:

sudo apt-get update
sudo apt-get dist-upgrade
sudo apt-get install chromium python-m2crypto

This checks for new software (update), upgrades anything necessary (dist-upgrade), and then installs two packages:

  • python-m2crypto — this will help speed up KA Lite a bit by helping out with encryption.
  • chromium — this is Google Chrome’s open source cousin, and it’s worth installing so that you can Google things as you go, and test things locally.

If everything goes to plan, you should now be able to find Chrome on the menu and navigate the web.


Install KA Lite

These steps are a shortened version of the official guide

Once Raspbian is running, these commands will download & install KA Lite:

git clone
cd ka-lite/

The download is 150MB, so allow a few minutes. The installer then prompts for a few questions, like:

  • “Do you wish to download the assessment package now?” — Say yes, it fetches another 500MB.
  • “Do you wish to set the KA Lite server to run in the background automatically when you start this computer?” — say “y”.

At the end, you will be given a command to start the server, which you should type in as well:

/home/pi/ka-lite/bin/kalite start

Once it starts (it will take a while!), it will give you two web addresses. One of them is local to the computer (127.x), and the other will work from other computers on the network. Write both of them down!

The install & start-up together will look like a this:


Test it out locally

Open up Chromium, and navigate to one of the addresses that the installer suggested.


Log in, using the details provided during the installation.


Click on “Manage”, then “Videos”


KA Lite will prompt for registration, which lets you download content. Use the “One click registration” on the left, then wait for it to connect.


Use the Videos section to fetch something. Here we fetch something from the ancient art & culture section:


Wait a few minutes before moving to the next section: The video downloads in the background.

Access over the network

From some other device which is on the same network, enter the web address that was given at the end of the installer (ignore the address which starts with 127.x — it wont work between two computers):

http://(IP address):8008/

From the browser, let’s test it out. Click over to Learn, and navigate to the video you just downloaded. It should display, so we can learn about those Egyptian artifacts:


This setup would be complete if you want to run on a wired network – you can simply bookmark this address on each computer which needs to use it, and manage it through the web.

Next post in this series: Raspberry Pi KA Lite wireless deployment

Howto: QRCodes on receipts with escpos-php

ESC/POS is a binary protocol for speaking to receipt printers. It contains a command for printing QR Codes on compatible printers. The PHP library escpos-php is used for generating these commands in PHP. This post will show you how to use it to generate QR codes on your receipt printer.

For printers which don’t support this command, a second option is available: sending the QR code as an image.

Getting started

First up, you need your receipt printer to be working with escpos-php. Here are some resources about how to go about that:

Option 1: Direct printing

This method sends QR codes directly. From the documentation, the syntax for this command is:

qrCode($content, $ec, $size, $model)

Print the given data as a QR code on the printer.

  • string $content: The content of the code. Numeric data will be more efficiently compacted.
  • int $ec Error-correction level to use. One of Escpos::QR_ECLEVEL_L (default), Escpos::QR_ECLEVEL_M, Escpos::QR_ECLEVEL_Q or Escpos::QR_ECLEVEL_H. Higher error correction results in a less compact code.
  • int $size: Pixel size to use. Must be 1-16 (default 3)
  • int $model: QR code model to use. Must be one of Escpos::QR_MODEL_1, Escpos::QR_MODEL_2 (default) or Escpos::QR_MICRO (not supported by all printers).

The below code snippets are directly from the QR code printing demo, showing how the output changes with the options given.

Simple example

This is the simplest use, with all default options. QR codes can be aligned in the same way as text or images on the page:

// Most simple example
title($printer, "QR code demo\n");
$testStr = "Testing 123";
$printer -> qrCode($testStr);
$printer -> text("Most simple example\n");
$printer -> feed();

// Demo that alignment is the same as text
$printer -> setJustification(Escpos::JUSTIFY_CENTER);
$printer -> qrCode($testStr);
$printer -> text("Same example, centred\n");
$printer -> setJustification();
$printer -> feed();

Data encoding

This is a demonstration of saving different types of data in a code. Numeric data is packed more efficiently than text. Binary data can also be stored.

// Demo of numeric data being packed more densly
title($printer, "Data encoding\n");
$test = array(
	"Numeric"      => "0123456789012345678901234567890123456789",
	"Alphanumeric" => "abcdefghijklmnopqrstuvwxyzabcdefghijklmn",
	"Binary"       => str_repeat("\0", 40));
foreach($test as $type => $data) {
	$printer -> qrCode($data);
	$printer -> text("$type\n");
	$printer -> feed();

Error correction levels

QR codes support fout levels of error correction. More error correction results in larger, but more durable codes:

// Demo of error correction
title($printer, "Error correction\n");
$ec = array(
	Escpos::QR_ECLEVEL_L => "L",
	Escpos::QR_ECLEVEL_M => "M",
	Escpos::QR_ECLEVEL_Q => "Q",
	Escpos::QR_ECLEVEL_H => "H");
foreach($ec as $level => $name) {
	$printer -> qrCode($testStr, $level);
	$printer -> text("Error correction $name\n");
	$printer -> feed();

Code size

The defauly codes are quite small. Each pixel can be blown up, up to 16x, using the size option:

// Change size
title($printer, "Pixel size\n");
$sizes = array(
	1 => "(minimum)",
	2 => "",
	3 => "(default)",
	4 => "",
	5 => "",
	10 => "",
	16 => "(maximum)");
foreach($sizes as $size => $label) {
	$printer -> qrCode($testStr, Escpos::QR_ECLEVEL_L, $size);
	$printer -> text("Pixel size $size $label\n");
	$printer -> feed();

QR models

QR models have different appearances, storage parameters and physical sizes. The default (Model 2) is most common. The printer used here does not support micro QR codes, and used Model 2 as a fallback.

// Change model
title($printer, "QR model\n");
$models = array(
	Escpos::QR_MODEL_1 => "QR Model 1",
	Escpos::QR_MODEL_2 => "QR Model 2 (default)",
	Escpos::QR_MICRO => "Micro QR code\n(not supported on all printers)");
foreach($models as $model => $name) {
	$printer -> qrCode($testStr, Escpos::QR_ECLEVEL_L, 3, $model);
	$printer -> text("$name\n");
	$printer -> feed();


To run the snippets, you need to initialise the printer, and define a title() function to print headings, like so:

/* Demonstration of available options on the qrCode() command */
require_once(dirname(__FILE__) . "/escpos-php/Escpos.php");
$printer = new Escpos();

// ....

// Cut & close
$printer -> cut();
$printer -> close();

function title(Escpos $printer, $str) {
	$printer -> selectPrintMode(Escpos::MODE_DOUBLE_HEIGHT | Escpos::MODE_DOUBLE_WIDTH);
	$printer -> text($str);
	$printer -> selectPrintMode();

Option 2: Printing codes as images

Not all printers can generate QR codes natively. The work-around is to generate a QR code as an image on the computer, and then send that image to the printer. This is slightly slower, so if you print a lot of codes, you should consider upgrading your printer.

First up, fetch a copy of phpqrcode and generate some codes. I wont attempt to document the whole library here, but in short, it supports most of the same features as the native QR command. To generate a code, you simply use QRcode::png:

QRcode::png("testing123", "test.png", 'L', 10, 0);

To print a PNG image, use the bitImage() command (the graphics command is also only available on newer printers):

$img = new EscposImage("test.png"); // Load image
$connector = ... // Add connector to your printer here
$printer = new Escpos($connector);
$printer -> bitImage($img);
$printer -> feed();
$printer -> text("Code printed from image\n");

$printer -> cut();
$printer -> close();

A more sophisticated way to hack in phpqrcode would be to add this new code as a different implementaton of the qrCode function. Other improvements are:

  • Use temporary files to avoid concurrency issues:
  • Where possible, expand the code on the printer, to send less data

class EscposQrImgPrinter extends Escpos {
	function qrCode($content, $ec = self::QR_ECLEVEL_L, $size = 3, $model = self::QR_MODEL_2) {
		// Validate inputs
		self::validateString($content, __FUNCTION__);
		self::validateInteger($ec, 0, 3, __FUNCTION__);
		self::validateInteger($size, 1, 16, __FUNCTION__);
		$model = self::QR_MODEL_2; // Only Model 2 supported in phpqrcode, change back to it.
		$sizeMod = 0;
		if($size % 2 == 0) { // Optimisation to enlarge codes on the priner, sending 1/4 of the data.
			$size /= 2;
			$sizeMod = self::IMG_DOUBLE_HEIGHT | self::IMG_DOUBLE_WIDTH;
		// Map error-correction to phpqrcode levels
		$ecMap = array(QR_ECLEVEL_L => 'L',
			QR_ECLEVEL_M => 'M',
			QR_ECLEVEL_Q => 'Q',
			QR_ECLEVEL_H => 'H');
		// Create QR code in temp file, and print it.
		$tmpfname = tempnam(sys_get_temp_dir(), "escpos-php");
		QRcode::png("testing123", $tmpfname, $ecMap[$ec], $size, 0);
		$img = new EscposImage($tmpfname);
		$this -> bitImage($img, $sizeMod);

This new class uses phpqrcode in the background instead, and can be accessed with the same function calls as the parent class:

$printer = new EscposQrImgPrinter();

$testStr = "Testing 123";
$printer -> qrCode($testStr);
$printer -> text("Most simple example\n");
$printer -> feed();
$printer -> cut();

$printer -> close();

The only visible difference between the implementations is a few pixels of spacing below the image.

Deprecated Google API’s: What you need to know

In less than a day, a whole series of old Google API’s are being switched off.

If you are running any of those API’s, then whilst this is bad news, you’ve had several years to upgrade (for example, the Provisioning API features have now been replaced by the Admin SDK). However, one of the API’s not mentioned on the linked page is the old ClientLogin API, which will also stop working on April 20.

ClientLogin involves directly sending a username and password to Google, and then receiving a login token back. There are two main categories of people who use the ClientLogin API which this post is targeted at:

  • People who haven’t figured out OAuth yet.
  • People using client libraries for the Google Data API’s, which are not deprecated, but often use this login.

If your use case involves users actually entering their username and password, then this post wont help (but this page will), but if you have an installed script which runs administrative functions on your domain, then read on, as it’s quite easy to retrofit your scripts with an OAuth2 service account.

Setting up a service account

Service accounts are designed for server-side use (ie, no browser), and replace using ClientLogin to authenticate as a super-admin for the domain.

First, log in to the developer console (, and create a new project, then jump to the credentials menu. Create and download a p12 private key.



Now under “Manage this Domain”, locate the advanced security options, and add a delegation for your new service account for one or more scopes. This allows the service account to access to a given API and act on behalf of users. As an example, the next section uses the Email Settings API, which has this scope:

And it’s added like so:





Example: How to retro-fit a PHP app with OAuth 2

Assuming you already have code which sends requests to an API, all we need to change is the Authorize: header. A ClientLogin request looks like this:

Authorize: GoogleLogin auth=<ClientLogin token>

But an OAuth2 request looks like this:

Authorize: Bearer <OAuth token>

You can generate a new token for yourself at the OAuth 2.0 Playground from Google to make sure your old API’s work with the new tokens (they will- any issues are probably permission or user problems).

So how do you generate one of these tokens for a service account? The best way is to use client libraries for this. In PHP, this is the google-api-php-client.

This library also has support for newer API’s (not older Google Data API’s), which you can use to replace your implementation where applicable. For this example, we’ll just be getting an access token.

First up, we need to do some structuring. I’ve wrapped old signature code into an abstract EmailSignatureUpdater class so that I can write two versions: The old ClientLoginEmailSignatureUpdater, and the new OAuthEmailSignatureUpdater, differing only by login method and Authorize: header.

So here is some ClientLogin code:

 * Functions dependent on ClientLogin, which will stop working after 2015-04-20.
class ClientLoginEmailSignatureUpdater extends EmailSignatureUpdater {
	 * @param array $conf Configuration for the Google login.
	protected function __construct(array $conf) {
		/* Getting account */
		$account = array(
				'accountType' => 'GOOGLE',
				'Email' => $conf['user']."@".$conf['domain'],
				'Passwd' => $conf['password'],
				'service' => 'apps');

		/* Log in */
		$login = $this -> login($account);
		if(!isset($login['Auth'])) {
			if(isset($login['Error'])) {
				throw new Exception("Google returned ".$login['Error']);
			} else {
				throw new Exception("Google login failed");
		$this -> token = $login['Auth'];

	 * Perform Google ClientLogin authentication
	 * @param array:string $account Account details (see top for components)
	 * @return string Response, including login token.
	private function login($account){
		/* Log in to google apps */
		$tk_ch = curl_init();
		curl_setopt($tk_ch, CURLOPT_URL, "");
		curl_setopt($tk_ch, CURLOPT_POST, true);
		curl_setopt($tk_ch, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($tk_ch, CURLOPT_POSTFIELDS, $account);
		$responseTxt = curl_exec($tk_ch);

		/* Parse response (very hack-y but works) */
		$responseLines = split('=', $responseTxt);
		$lastkey = false;
		for($i = 0; $i < count($responseLines); $i++) {
			$line = $responseLines[$i];
			if($i == 0) {
				/* First line is just a key */
				$lastkey = $line;
			} else {
				$vals = split("\n", $line);
				if($i != count($responseLines) - 1) {
					/* Split into value and next key */
					$nextkey = $vals[count($vals) - 1];
					unset($vals[count($vals) - 1]);
				} else {
					$nextkey = false;
				$response[$lastkey] = implode("\n", $vals);
				$lastkey = $nextkey;
		return $response;
	protected function authorize() {
		return 'Authorization: GoogleLogin auth='.trim($this -> token);

And the part you’re probably searching for: how to get an access token out of the google-api-php-client:

 * New OAuth2 authentication using google-api-php-client to get us logged in instead.
class OAuthEmailSignatureUpdater extends EmailSignatureUpdater {
	protected function __construct(array $conf) {
		$this -> token = $this -> login($conf);
	private function login(array $conf) {
		require_once(dirname(__FILE__) . "/vendor/google-api-php-client/src/Google/autoload.php");

		// Start client
		$client = new Google_Client();
		$client -> setApplicationName("Test Application");
		// Load key
		$key = file_get_contents($conf['key_file']);
		if(!$key) {
			throw new Exception("Key could not be loaded from file " .$conf['key_file']);
		// Set up auth with scopes
		$gauth = new Google_Auth_AssertionCredentials(
		// sub- pretend to be a user
		// Should probably be the same as the user you logged in as with ClientLogin
		if(isset($conf['sub'])) {
			$gauth -> sub = $conf['sub'];
		$client -> setAssertionCredentials($gauth);
		if($client -> getAuth() -> isAccessTokenExpired()) {
			$client -> getAuth() -> refreshTokenWithAssertion($gauth);
		$client -> setClientId($conf['client_id']);
		/* Save token for later use */
		$token = $client -> getAccessToken();
		if (!$token) {
			throw new Exception("Google apps login failed!");
		$arr = json_decode($token);
		if(!isset($arr -> access_token)) {
			throw new Exception("Google apps login did not return access token!");
		return $arr -> access_token;
	protected function authorize() {
		return 'Authorization: Bearer ' . $this -> token;

In the superclass, we provide a getUpdater() function to dish out an old or new updater based on the configuration. In future releases, you could just throw an Exception instead of logging in with ClientLogin, as you know it will fail!

 * Contains email signature updater methods, with no login method
abstract class EmailSignatureUpdater {
	 * @var string The login token.
	protected $token;

	 * @param array $conf The configuration to use.
	protected abstract function __construct(array $conf);

	 * Return authorization header
	protected abstract function authorize();

	// A series of methods which make raw HTTP requests
	// to were
	// located here, and are not relevant to this post.
	 * Based on the configuration, return a signature updater which logs in using the correct API.
	 * @param array $conf
	static function getUpdater(array $conf) {
		if(isset($conf['user']) && isset($conf['domain']) && isset($conf['password'])) {
			return new ClientLoginEmailSignatureUpdater($conf);
		} else if(isset($conf['service_account']) && isset($conf['client_id']) && isset($conf['key_file'])) {
			return new OAuthEmailSignatureUpdater($conf);
		throw new Exception("Configuration insufficient for loading email signatures. See config.php.example.");

To utilise this, you need to change HTTP methods to care less about where their headers come from. I was using cURL for this, but on any library, you need to set the header using the new authorize() function before you send off the request:

curl_setopt($ch, CURLOPT_HTTPHEADER, array($this -> authorize(), ..., ...);

The idea is that users can simply alter their configuration to pick up the newly supported OAuth, allowing you to shift it from a software problem to an administrative/configuration problem:

/* Google apps domain config */
/* Old style ClientLogin usage (deprecated) */
//$config['google']['user'] = "admin";
//$config['google']['domain'] = "";
//$config['google']['password'] = "...";

/* New login details for OAuth */
$config['google']['service_account'] = '';
$config['google']['client_id'] = '';
$config['google']['key_file'] = dirname(__FILE__) . '/google-key.p12';
$config['google']['sub'] = ""; // optional

Within your application, you then construct a new any-authentication object based on the configuration, and call its old methods as normal:

$updater = EmailSignatureUpdater::getUpdater($config['google']);
$updater -> doThing('param1', 'param2', etc);

Good luck!