Category Archives: web development

split testing

I wrote a split-testing plugin (also known as “A/B testing”) for my CMS early last year. It wasn’t very good, so I wrote an external split-testing tool instead, which you can you for your own websites if you want.

Split-testing application

It works similarly to Google’s “web optimiser”, but I think it’s easier to use.

As a test, I chose to optimise the front page of KV Sites, to see if I could encourage people to contact me or read other pages on the website.

In particular, I wanted to see if it was better to explain what I do, or to assume that the reader knows and just wants to get on with.

As an example, consider the following two extracts:

Indirect speach – explaining what I do

Web Development

Reduce costs by automating and networking your business.

Proven record, with a number of large projects completed. Example projects include Duffy Transport's management application, the crop prediction software used by Cropworks, ongoing development of the WebME CMS, and technical support for a number of projects by other web development companies.

vs.:

Direct speech – asking what the reader wants

I am looking for Web Development

If you are looking for an online solution which to reduce your office expenses, we have experience writing solutions which can cut hours of work per day off your load. Read more about our web application development here.

It seems obvious that the direct speech version would work better, but when your job is involved, it’s better to be certain than to work based on assumptions.

So, I set up a split test. On the homepage of KV Sites, I sent the HTML for both versions to the browser, and set the different versions to display randomly using CSS.

Each version includes a “more info” link (of sorts), so I added the “conversion” code (which records when people go to the page you want them to) to the pages they were linked to, and started recording.

It took a few weeks for the information to come in, as my site does not have heavy traffic, and I didn’t want to artificially boost it in any way, but here’s how it turned out:

Name Visitors Conversions
front page direct marketing 237 v2: 12
v1: 24

It’s obvious from the above that “v1″ (the direct speech one) is twice as effective as “v2″ (indirect speech).

I’m very encouraged by these results. They mean that it is possible to both a) improve “conversions” based on text changes, and b) provide numbers proving those results.

code golf

I came across a new (to me) game yesterday – Code Golf.

The game involves coming up with an algorithm to solve a programming problem, and trying to condense the code for the algorithm into the smallest number of bytes possible.

The first one I tried was this. It was a fascinating problem, and took me a day of musing on it (in the back of my head as I did other things) before I had a solid solution.

After writing the solution, which took 1380 bytes, it was time to start “golfing” it.

At first, I thought I’d try my compressor on it. This shrank it to 825 bytes, but after compression, it couldn’t be worked with anymore, so I thought I’d try compressing it manually.

This resource was fascinating, and gave me a load of pointers.

There were a few small points I came up with myself while working on it:

I prefer to use “\n” instead of “;” for command endings, as it makes code more readable. (the game is about shrinking the code, not obfuscating it)

A saving can be had by combining nested loops:

// before
for(i=5;i--;)for(j=5;j--;)M[i][j]=0
// after
for(i=25;i--;)M[0|i/5][j%5]=0

If you need to push into an array on multiple lines, make a shortcut for the push method:

// before (example)
a=[]
cond1()&&a.push(1)
cond2()&&a.push(2)
cond3()&&a.push(3)
cond4()&&a.push(4)
// after
a=[]
P=a.push
cond1()&&P(1)
cond2()&&P(2)
cond3()&&P(3)
cond4()&&P(4)

If possible, find a maths way of identifying interesting points, instead of comparisons.

// before
if((x==4&&y==4&&z==3)||(x==4&&y==3&&z==4)||(x==3&&y==4&&z==4))dosomething()
// after
if(x*y*z==48)dosomething()

I think this game is really interesting, and it will sharpen my own skills as a programmer, as it taxes the mind not only to find the solution to a problem, but also to express that solution as concisely as possible.

In the end, I was able to solve the problem in 668 characters – that’s 142 characters less than my compressor was able to manage.

musical intervals trainer, web version

last weekend, I wrote an intervals trainer app for practicing recognising intervals.

I want other people to use it, but haven’t got a Google development account yet so can’t upload an app.

So, today, I improved the app and made a web-accessible version.

try it out!

it’s designed to move up from very simple intervals (major/minor 2nd intervals, with only natural notes) to more difficult intervals (diminished/augmented, with double sharps and flats), but it’s also designed to only get more difficult at a rate that /you/ can manage.

to do this, the app uses a “levels” system, where each level has one more extra type of interval or note type, and you are tested on them. over 50% of the time, the question will be from the level you’re on, and the rest of the time, the question will be randomly chosen from every other level that you have already passed.

get 10 in a row correct, and you go to the next level.

but, get 5 wrong in a row, and you go down a level.

at the moment, there are 24 levels – all the way up to augmented 8ths – can you get through all the levels?

give it a try!

Adding a trigger-based plugin to WebME

One of my clients has his own fork of WebME that he keeps current with the SVN version.

He mentioned a collision recently, where a hack he had written into the online store plugin was overwritten by updates.

So, in this post, I’ll demonstrate how to add a plugin that uses a trigger to run some code.

First, we define what needs to be done.

The client wants that when an order in an online store has been processed, an email is sent out to that client.

This immediately points out where the trigger point goes. The processing of orders is done in the file ww.plugins/online-store/verify/process-order.php, so we need to put the trigger in there as well, at the end of the OnlineStore_processOrder() function:

  Core_trigger('after-order-processed', array($order));

What happens at that point is that the CMS will check all plugins to see if there are any that have a trigger of the name “after-order-processed”, and if there are, then that trigger will be fired.

So, next we need to create the plugin. In fact, it’s so easy I’ll just write it straight out. I’m calling this one “DemoPlugin”, so we start by creating the directory /ww.plugins/demo-plugin”, and placing the file plugin.php in it:

<?php
$plugin=array(
  'name' => 'DemoPlugin',
  'triggers'      => array(
    'after-order-processed'=>'DemoPlugin_afterOrderProcessed',
  ),
  'description' => 'Sends an email after an order is processed',
);

function DemoPlugin_afterOrderProcessed($PAGEDATA, $order) {
  mail('kae.verens@gmail.com', 'subject line', print_r($order, true));
}

Simple!

Now, in order to do this, I edited one file which is part of the “official” WebME package, to add the trigger. If you find you need to do this, please contact me and tell me what you’re trying to do, and what you edited, so I can add it to the SVN version and not break your code in future releases.

FB and G+, the new OS-wars

Back when Linux was a gangly youth, there was a great excitement every time you did an update. Unlike Windows and Mac with their expensive three-year-nothing-then-a-service-pack-with-cool-stuff routines, in Linux, there were so many cool free packages around, and /every one/ of them would have something new almost every week.

So, I spent quite a lot of time compiling and recompiling, everything from wget up to the KDE behemoth. And I’d be reading the weekly release notes as well to see if there was any new trick out that week.

I can’t tell you how excited I was when I first installed a copy of Linux where I didn’t have to configure X11 using a text-mode Xconfigureateur!

Or when I recompiled my kernel the first time, or when I recovered from a bad update straight from the GRUB command-line. Or the first time I ejected a CD from across the room (logged in remotely), or freaking out the wife by playing some music on her laptop from a different room.

In the last few years, Linux development has matured, though, so there’s not the same edge-of-the-seat excitement that there used to be, but I think there’s still hope for the techadrenaline junkies out there, because Facebook and Google+ are the new cool, and there’s a /ton/ of stuff that can be done with that!

My eyes are on how FB and G+ evolve. now that FB has competition, I expect some /really/ cool stuff is going to come out of the woodwork.

first and last saturday of a month

I’m working on an expenses application. In order to do it, I need to display the entire month, with full weeks in each (from Saturday to Friday).

To do this, I need to know what date the Saturday in the first week falls, and the date of the first Saturday in the following month.

Here’s the code (assuming year is a 4-digit year, and month is a 1-12 number):

      // { start date
      var start=new Date(year, month-1, 1);
      var day=start.getDay();
      day=(day+1)%7; 

      start=new Date(start-3600000*24*day);

      // }
      // { end date
      month++;
      if (month==13) {
        month=1;
        year++;
      }
      var end=new Date(year, month-1, 1);
      var day=end.getDay();
      day=7-((day+1)%7);

      end=new Date((+end)+3600000*24*day);

      // }

can’t be bothered explaining it – just trust that it’s right ;-)

separating buttons in jquery-ui dialog

By default, the jQuery-UI dialog will place buttons on the right side of the popup:

This causes a problem because if you have “OK” right next to “Delete”, and you click the wrong one, well …

The obvious solution is to move the “Delete” to the opposite side.

To do that, add the following two lines after creating the dialog:

$('.ui-dialog-buttonset').css('float','none');
$('.ui-dialog-buttonset>button:last-child').css('float','right');

Now the buttons are on opposite sides:

installing WebME in Fedora 16

I got a new laptop today, and as I’ve still got work to do, I need to get the system up and running so it can install WebME.

Here’s a minimal instruction set for installing WebME on your Fedora computer.

As ‘root’, run this in a console:

yum install httpd mysql-server php php-gd php-mysql php-pear-Log php-xml svn
echo "127.0.0.1 kvwebme" >> /etc/hosts

Then edit /etc/selinux/config, change “enabled” to “disabled” and restart your machine.

Login as your normal user, run this in the console:

mkdir ~/websites && cd ~/websites
svn co https://kv-webme.googlecode.com/svn/trunk/ kv-webme
chmod 755 /home/kae

‘su’ to ‘root’ again. Add this to /etc/httpd/conf/httpd.conf:

NameVirtualHost *:80
<Directory /home/kae/websites>
  AllowOverride All
</Directory>
<VirtualHost *:80>
  ServerName kvwebme
  DocumentRoot /home/kae/websites/kv-webme
</VirtualHost>

And finally, in the console again:

service httpd start
service mysqld start
chkconfig --level 35 mysqld on
chkconfig --level 35 httpd on

That’s it – your system is set up. From that point, just go to http://kvwebme/ and follow the instructions from there!

onchange in ckeditor

I needed to track changes to source in a CKeditor instance, as my recent work uses a lot of “on-the-fly” updating.

Using Alfonso’s onChange plugin, it was a simple matter to capture changes when in WYSIWYG mode.

But that doesn’t work in source mode.

Assuming you’re using the jQuery extension for CKeditor (and if not, why not?), you can capture source mode changes by adding this to your CKeditor’s config.js:

$('textarea.cke_source').live('keyup', function() {
  $(this)
    .closest('.cke_wrapper')
    .parent()
    .parent()
    .prev()
    .ckeditorGet()
    .fire('change');
});

jQuery maskImage plugin

I had a need today to write some code which involved masking one image with another, dynamically.

There is no simple way to do this in JavaScript. The nearest I came to finding working code online that does it was edge.js, but that’s not free.

So, I wrote my own.

demo

Download: zip (25k), bz2 (24k)

In the demo, what’s happening is that an image such as this:

is being used as a mask for another image:

to create a masked image:

For Firefox and Chrome and other recent browsers, it works using pure JavaScript (even works on the iPhone).

For Internet Explorer (sigh) you need to do a little bit of server-side setup.

Basically, on the server-side, make sure you have PHP installed, with the iMagick extension, then make the ‘cache’ directory writable by the server.

To use, insert an image into your document:

<img id="image-id" src="an-image.png" alt="" />

And then apply the mask using jQuery:

$('#image-id').maskImage({src:"the-mask.png"});

Simple, innit! That’s a few hours of my own life dedicated to saving a few minutes of yours ;-)