27 Mar

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.

24 Mar

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!

14 Mar

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.

08 Nov

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.

21 Oct

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 😉

12 Oct

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:

05 Oct

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 zip unzip
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!

31 Aug

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');
});
25 Aug

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 😉

13 Aug

new API for WebME

As I said in the last post, an API would be required to make the system more testable and more consistent.

I started straight away and wrote up something quickly. Over the next week, it solidified into something that appears to cover any needs that I have.

So here’s how the API works:

Requests are sent to a URL which is generated like this:

/a
[/p=plugin-name]
/f=function-name
[/other-parameters]

The plugin name is optional. Leaving it out means you want to call a core function.

Parameters can be added by adding /key=value pairs to the URL.

An example URL might be this:

/a/f=login/email=kae@verens.com

Sending that, with a POST parameter for the password, will log me in.

To log out, I can use this URL:

/a/f=logout

Simple!

Function Names

mod_rewrite is used to direct a request through a script which tears the URL apart into parameters.

If a p parameter is given, the function is named after the plugin, rewritten to match the WebME coding standard.

For example, if the URL is /a/p=comments/f=editComment, then the “comments” part is rewritten as Comments, and ‘_’ and “editComment” are appended to form the function name “Comments_editComment”, which is called and the result returned to the browser.

For double-barrel plugin names, such as “image-gallery”, the name is rewritten to “ImageGallery”.

If no p parameter is given, then the request is a core function, and “Core_” is prepended to the function name.

For example, the login URL above, /a/p=login calls the function Core_login.

If a function name begins with “admin”, it is an admin function (see below for more on this).

File names

If no plugin name is supplied, then the core API file, /ww.incs/api-funcs.php is loaded. This contained common API functions that might be used by any core script or plugin.

If a plugin name is supplied, then the API file is expected to be located at /ww.plugins/plugin-name/api.php for common functions, and /ww.plugins/plugin-name/api-admin.php for admin functions.

For core functions, common functions are at /ww.incs/api-funcs.php and admin functions are at /ww.incs/api-admin.php

Security things

Having a central point for RPC means that we can apply security rules in one place and know that they cover all scripts. Before-hand, I would sometimes come across scripts and realise that they were open for abuse if someone knows that magic URL incantation. I would silently curse myself or whoever had written the script and fix it up. Now, though, having one single point of entry means I can secure everything at once.

If a function name starts with “admin”, then the script checks to see if the user is logged in and is a member of the administrators group. If not, the API will return an error. It’s as simple as that!

Of course, this doesn’t stop abuse by people that are logged in as admins or who are victims of XSS, but it helps stop a few problems caused by developers not noticing their scripts were open to use by anyone at all.

Conclusion

So now, when people are creating new plugins for WebME, the following could be used as a bare-bones directory structure:

/ww.plugins/plugin-name/plugin.php    details, server-side functions
/ww.plugins/plugin-name/api.php       common RPC functions
/ww.plugins/plugin-name/api-admin.php admin RPC functions
/ww.plugins/plugin-name/admin.js      admin scripts in JS