Latest posts

Woha – nearly a year! CKEditor and A4 paper size. - March 4th, 2013

Nearly a year since I last blogged. Phew, caught it just in time ;-)

First time this year (2013) I got to drive home without my lights on. The clocks haven’t even gone back yet! Woo-hoo for springtime :)

So today’s topic, CKEditor and A4 paper. Mmm-hmm. Letter paper, A4, A5, in fact any size. You want to let someone WYSIWYG edit layout on a piece of paper, envelope, acetate, banner, badge or whatever. Sure, we can do that!

<script type="text/javascript">
CKEDITOR.on('instanceReady', function() {;
var iframe = $('#cke_editable_area iframe').contents ();
iframe.find ('html').css ({
'background-color': '#b0b0b0'
iframe.find ('body').css ({
'width': '297mm',
'height': '210mm',
'background-color': '#ffffff',
'margin': '0mm',
'padding': '5mm'

Yee-haa cowboy. The above uses the CKEditor instanceReady event and some jQuery magic (not optimally written :) ) to force the width/height of the editable area. Unfortunately text can flow past the bottom (but not off the sides or top) – but that’s probably a good thing, else the user would not “see” that they’ve made a mistake.

Some grey colouring gives the illusion that you’re working with your favourite text editor.

Shove the result to a fresh page with the following CSS for printing, certainly with Chrome – works like a champ. (Note I’m using A4 measurements in the JavaScript, so the CSS below is to match that.)

body {
font-family: sans-serif, Arial, Verdana, "Trebuchet MS";
width: 297mm;
height: 210mm;
background-color: #ffffff;
margin: 0mm;
padding: 0mm;

@page {
size: landscape;
width: 297mm;
height: 210mm;
margin: 5mm;

UPDATE: further information on how I achieved this has been requested … what I ended up with (after much fiddling) was a 95% accurate “what you see is what will print” … using a kludge of ugly tricks.

The main JS:

<script type="text/javascript">
// ON CKEDITOR READY: Sets up page size and white colour background in edit area
CKEDITOR.on('instanceReady', function() {;
	var iframe = $('#cke_editable_area iframe').contents ();
	iframe.find ('html').css ({
		'background-color': '#b0b0b0'
	iframe.find ('body').css ({
		'width': '297mm',
		'height': '420mm', //was 210 ****
		'background-color': '#ffffff',
		'margin': '0mm',
		'padding': '5mm'
	iframe.find ('td').css ({
		'padding': '-1px'

That generates a landscape A4 page, editable in your browser.

To print, I pass the content (HTTP POST, basically) into a printable page:

<html lang="en" dir="ltr">
   <!-- the following stylesheet is provided by ckeditor - and provides some sane defaults for displaying -->
   <link rel="stylesheet" type="text/css" href="/css/ckeditor.css" />
     class="cke_contents_ltr cke_show_borders"
     style="width: 297mm;
       height: 420mm;
       background-color: rgb(255, 255, 255);
       margin: 0mm;
       padding: 5mm;
       cursor: auto;">
        style="width:1120px; border:none;"
         <?php print $contents; ?>

The CSS referenced is vanilla from CKEditor.

Adjusting Timemachine size on ReadyNAS Duo - March 25th, 2012

I have a ReadyNAS Duo, and several Mac devices backing up to it (via the typically “Apple awesome” Time Machine feature).

I recently upped the allocated disk space in FrontView to 300GB, from 120GB – which while each Mac’s Time Machine preferences said “NAS device, 300GB” – claimed the disk didn’t have enough “temporary space” to perform the backup.


I got SSH access to the ReadyNAS working – (I used Enable SSH plugin), and took a look around the filesystem.

It appears in classic OSX style, Apple have opted for a simple .plist info file:

cat /c/.timemachine/Matthew\ Hall’s\ MacBook.sparsebundle/Info.plist

Upping the value to the match the new disk size (300*1024*1024*1024), solved the issue.

Presumably (speculation) OSX treats the .sparsebundle directory as a disk image – and the Info.plist defines how “big” the disk image is – even though its a directory (can anyone confirm?). Thus the “disk” was indeed 300GB, but the existing backup image was only 100GB …

Shame Netgear / Apple didn’t put something obvious to allow updating the .plist file, but never mind! Problem solved …

Argos - January 30th, 2012

“It’s like playing Bingo, only you you win what you’ve already paid for!”

– Michael McIntyre

MySQL migrations and generating Zabbix Cisco templates - December 7th, 2011

What a week. What a month. What a year.

So much has happened, far more than I could or should ever write about.

Recently we’ve been migrating MySQL servers from one hardware to another – for anyone (me!) that finds this useful in the future, firstly “Hello, and I hope the future is better than the current ‘past’!”, and secondly “I hope this does what you need”:

mysql -h "$HOST" -u "$USER" -p"$PASS" -e \
user,\"'@'\",host,\"'\;\") FROM mysql.user;" -B -N | \
mysql -h "$HOST" -u "$USER" -p"$PASS" | egrep -v "^Grants"

That small bash script accepts 3 arguments, HOSTNAME, USERNAME and PASSWORD. Executing it will output “CREATE USER” statements for all users on the MySQL instance.

While migrating the MySQL servers, we took the opportunity to setup a new monitoring solution – Zabbix. I’ve used it a couple of times in the past, and in my most humble opinion it’s failing is it’s flexibility. It’s just so flexible!

We have a fair number of Cisco switches and routers at our disposal here in the office, and setting up Zabbix templates for each is not high on my bucket list. Why do something by hand that can be done automagically by a computer?

Thus this (very hacky, PHP) script which automatically generates Cisco (SNMP) templates for Zabbix.

Simply run “show snmp mib ifmib ifindex” on your Cisco device of choice, and shove the output into the script’s STDIN. Hey-presto, out comes a Zabbix template!

Modifying the default options in the template is very easy; just edit what you like after line 34.

Samba 3, Windows 7 and Domain Admins - July 7th, 2011


It’s been for several weeks that I’ve been trying (and failing) to aquire Domain Admin status on our Samba domain.

With Windows 2000 and XP, administrative access was easy.  A local admin account called “administrator”, and a local policy stating who’s an administrator – all peachy.

You can tell I’m not a Windows administrator by job!  Obviously domain admins is a far cleaner way to go.

So I dip my toe into Windows 7 on a Samba 3 domain.

It works well.  Too well.  There’s a small issue with the workstations claiming “there’s no logon servers available to handle the request” for 60+ seconds from a cold-start, but I think that’s solvable (I suspect WINS, NetBIOS or DNS is failing to warm up in a timely manner).  The domain admins however eluded me.

“So it’s OK” I think to myself.  “Login as the local administrator – set some local policies up.  …  Oh wait, Windows 7 disabled those because I joined the domain and didn’t first give them passwords.  Sheesh!  Joining the domain admin group it is then.”

Well I searched the Internet and ripped my hair out.  Week after week the issue prevailed.  Windows 7 wouldn’t obey the “Domain Admin”.  “Elevated access required.”

Finally I trip across this:

The second guy motions that “Domain Admins” must be group ID 512 (in the Windows mapping) – and blam.

One Samba restart later … all works.

Check the documentation out at … specifically you’re looking for something like this:

net groupmap add rid=512 unixgroup=MYUNIXGROUPHERE type=domain

Playstation Network nearly back online – - May 15th, 2011

As I sit here typing, the very Playstation Network (PSN) service which has received so much flak over the last month is finally approaching usability once more.

I would like to say a huge thank-you to the guys at PSN, there’s no question over how hard you’ve been working to get things this far. Despite how many will disagree with me, I’d like to thank the non-tech guys at Sony too, for your honesty and speed with dealing with things.

I work at a PCI-DSS regulated company myself, as a programmer, and don’t have 1% of the customers PSN does. We also don’t provide a service that millions of people rely on “real-time” for entertainment purposes, nor which they expect to find working 24/7.

You guys have done a good job, please keep it up.

This could have happened to anyone, although it’s always easy to point the finger when you’re the ignorant customer.

Kate and Will – they made it! - April 29th, 2011

Yeah yeah, wasn’t going to watch it and all that – but I finally broke.

Don’t they just look great :)

Validating email addresses by SMTP in realtime - April 6th, 2011

Validation of email addresses.  What a painful subject.

About a year ago I looked into the possibility of using SMTP to validate email addresses.  As it turns out, it’s not perfect (a lot of false-positives) but it’s very reliable (I’ve failed to get any false-negatives).

The following code outlines how this works (written in PHP, because I was thinking about it in the context of web-apps):

function validate_email_regex ($email) {
   return preg_match ('/\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b/i', $email);

function validate_email_smtp ($email) {
   if (!validate_email_regex ($email)) return false;
   list ($user, $domain) = split ('@', $email);

   if (!getmxrr ($domain, $mxhosts)) return false;
   $i = 0;
   $fp = false;
   $thishost = isset ($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : exec ("hostname");
   foreach ($mxhosts as $mxhost) {
      if (++$i > 3) break;    // don't check more than 3 MX records
      if ($fp) fclose ($fp);  // cleanup from last iteration

      $fp = fsockopen ("tcp://$mxhost", 25, $errno, $errstr, 10);
      if (!$fp) continue;
      if (!$str = fgets ($fp)) continue;
      if (substr ($str, 0, 3) != '220') continue;

      fwrite ($fp, "HELO $thishost\r\n");
      $str = fgets ($fp);
      if (substr ($str, 0, 3) != '250') continue;

      fwrite ($fp, "MAIL FROM:<mail@$thishost>\r\n");
      $str = fgets ($fp);
      if (substr ($str, 0, 3) != '250') continue;

      fwrite ($fp, "RCPT TO:<$email>\r\n");
      $str = fgets ($fp);
      if (substr ($str, 0, 3) != '250') {
         fclose ($fp);
         return false;  /* don't proceed with other MX records because of a bad user */

      fclose ($fp);
   return true;

SVN hooks – receiving HTML formatted emails when SVN commits are made - April 5th, 2011

While setting up Trac as our company source-code repository yesterday, the question arose of “What about cute HTML emails when SVN commits are made?”.

Hmmmm.  Thank goodness for SVN hooks – a wonderfully understated feature of subversion!

Go to your subversion directory (that created by “svnadmin create”), and enter the “hooks” directory.

Create a file, executable and owned by your webserver, called “post-commit”:

touch post-commit
sudo chown www-data:www-data post_commit     # RH and other distros will want apache:apache here
chmod +x post_commit

Enter the following as it’s content (this is a fairly self explanatory shell script):

#!/bin/sh set -e REPOS="$1" REV="$2" TO="" FROM="" BY=`svnlook author $REPOS -r$REV` MSG=`svnlook log $REPOS -r$REV` CHANGED=`svnlook changed $REPOS -r$REV` DIFF=`svnlook diff $REPOS -r$REV | pygmentize -l diff -f html` STYLE="borland" CSS=`pygmentize -S $STYLE -f html` echo "To: $TO\nFrom: $FROM\nSubject: SVN commit r$REV - ($BY) \"$MSG\"\nContent-Type: text/html; charset=us-ascii\n\n<html>\n<style type='text/css'>\n$CSS</style>\n<body>\n<p><a href='$REV/'>View changeset r$REV on Trac</a></p>\n<h3>Files changed:</h3><pre>$CHANGED</pre>\n<h3>Changes made:</h3><p>$DIFF</p>\n</body>\n</html>" | /usr/sbin/sendmail -t

You’ll need to apt-get or yum install pygmentizer (package named python-pygments on Debian/Ubuntu) to get the cool diff colouring.

And that’s it!  (The “sendmail -t” reference works with Exim on Debian Squeeze, your mileage as always, may vary.)

Improving CoovaAP portal pages for iPhone and Android - March 19th, 2011

Over the last couple of weeks, I’ve been spending my spare time playing with the Coova AP (ChilliSpot) wireless hotspot service on a WRT54GL.

The main problem I’ve had with it is the portal pages not looking so good on mobile devices (particularly iPhone and Androids).

A little bit of Googling revealed a solution (at least, a solution for websites in general): insert the following meta tag into the HTML header.

<meta name="viewport" content="width=320; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;" />

In the CoovaAP configuration interface, you can apply this for every portal page by adding it to the “HotSpot”/”Portal”/”HTML Title”.