Friday, June 20, 2008

RPNBuddy returns as RPNChat

A long, long time ago I created an IM buddy called RPNBuddy that implements a reverse polish notation calculator as a chat bot. It ran for a while on one of my machines but didn't get a whole lot of use.

A few months ago, Hans Nordhaug, an associate professor at Molde University College in Norway, wrote to ask what had happened to RPNBuddy. I offered him the source code under the General Public License and he readily accepted, improved it and has now relaunched the service as RPNChat.

Connect to the RPNChat buddy on AIM and you can use it as a calculator. Here's a session of me calculating Roger Bannister's average speed in mph when he ran the under 4 minute mile in 1954 (3 min 59.4 s).


Tuesday, April 22, 2008

Bookmark-based registration

Recently, I've been learning Ruby on Rails and I can never learn anything unless I build something with it. I also recently read Programming Collective Intelligence and had a desire to use some of those algorithms too.

I'll post more about the actual web site I created another time; currently it's in alpha form running on Heroku. The web site is used for naming babies, the initial alpha-release is the girls' names only site EmilyOrEmma? which uses "Hot or Not" style voting and manages to incorporate in one page the Levenshtein distance, Metaphone algorithm and both item-based and user-based filtering.

But my biggest bug bear with baby naming web sites is the need to create an account. You can browse baby names all you want, but as soon as you want to do something like add a name to a list of favourites you are forced into registration. Or you don't have to register but anything you do is ephemeral.

For my site, I came up with a better solution: bookmark-based registration. If you visit the site you'll see at the bottom of every page a link to bookmark. This link is unique to you. It contains your user id and a hash which I used to prevent forgery.

Bookmark this link and you can return to your recommendations, saved names, etc. any time.

Labels: ,

Friday, September 07, 2007

Wildfire has launched

I wrote the other day about what I saw as the problems with social news web sites and my proposed alternative. That alternative, the Facebook application called Wildfire has now launched.

Based on feedback from users a couple of changes have been made:

1. The standard page you see is a random selection of stories, you can pick any of these and forward them to your friends and display them in your profile.

2. Wildfire will now pull down RSS feeds you specify and build your "My Fires" list so that you can choose to forward some or all of the stories from RSS. RSS feeds are pulled down twice a day.



Tuesday, September 04, 2007

The problems with social news

I recently launched my own 'social news' application, call Wildfire. I did this because looking around at existing social news sites like Digg and Reddit I felt like they left a lot to be desired.

Before telling you about Wildfire, let me tell you what I think it wrong with social news as it stands:

1. The Wisdom of Crowds incorrectly implemented

It seems to me that most people who use the phrase "Wisdom of Crowds" haven't read the book, or if they have read the book they haven't understood the concept. For me, social news sites fail to produce interesting links because they rely more on herd mentality than WoC.

If you visit the front page of Digg or Reddit you are being presented with already filtered news and you are offered the opportunity to 'digg' stories you like. This is on the on-line equivalent of going to the same restaurant as everyone else, just because it's full. Digging a front page story is pointless.

The WoC partly relies on not knowing what other people think. Galton's ox-weight-guessing relied on averaging the opinions people gave of an ox's weight without collaboration. All current social news sites fail because they expose other people's votes to readers.

If social news sites really wanted the WoC they'd present users with a random selection of news stories and ask them to vote. Then they'd get to see the top stories without a chance to vote. Of course, no site is likely to do that, what people want is an instant page of links.

2. Misplaced downvoting

Reddit has the ability to downvote a story. This has a two-fold effect: it reduces the number of votes on a story (and thus its position on Reddit) and it trains the collaborative filter that Reddit uses to give recommended use. This is a mistake.

Either downvoting is a way of telling the world you think a story is unworthy, or it's for personalization. You might think they are the same thing: surely if enough people don't want a story then their personalization is the same as the global view. Wrong. Only if you can assume that my world view is your world view. Which leads me to...

3. No social aspects

There isn't one society. Society is covered (in a topological sense :-) by many overlapping societies. Yet social news sites have a 'one size fits all' mentality.

Each social news site has a personality and you have to choose the site that best fits your views. Reddit is very left learning and, frankly, a bit snobbish. Digg is younger, more raw, and more low brow.

You shouldn't have to choose the site that fits your personality. The site should tailor to you.

4. No homophily

We tend to associate with people who have similar tastes and views to us. This is known as homophily. Current social news sites fail to deliver on the power of homophily. The reality is that my interests are closely aligned with my friends' interests, and not with some one size fits all view of the web.

Currently with their badly implemented WoC, missing social aspects and lack of homophily social news doesn't deliver.

Sure, social news is hot: any filter is better than having none, but that doesn't make it good. Which brings me to Wildfire.


Wildfire is a social news application built inside Facebook. It works as follows:

  • Wildfire users submit stories by giving a URL and a title (just like any news site)
  • Submitted stories are automatically spread to the submitter's friends (and appear in the friends' profiles)
  • Friends can choose to further spread news they receive to their friends. When the do this the original submitter (and every up the chain who spread the news) get a point of karma. This means that karma is only gained when your friends think a story you spread (or submitted) is worth spreading further.
  • You see two views of stories: those that were spread to you (and hence should be relevant because of homophily) and the 'global view' (called Major Fires) which are the top stories across all users.

Wildfire is designed to deliver you a small number of stories that you'll care about. These appear in your Facebook profile. Currently, I have not submitted Wildfire to Facebook for approval because it needs testing. If you use Facebook and want to try it out please add Wildfire and give me your feedback.


Wednesday, July 18, 2007

Adding application ratings to Facebook Applications

I have a few Facebook applications which have a modest number of users (Easter Egg, Four Secrets, One Lie and My Days) and it started to annoy me that Facebook does not have a way for users to rate applications.

Well, now they do.

A Free Service

I've put together a little service that allows any Facebook application developer to have their app rated by users and display the rating on their application's About Page. To see how this works take a look at the About Page for My Days. At the bottom there's a section where the current application rating is shown, and the user is given the chance to vote on the app.

All the voting takes place on my server, and I've managed to create HTML that the About Page will accept that dynamically updates the voting as people vote.

Adding rating to an application's About Page

If you have a Facebook application and want to have voting on your app., then simply add the follow HTML to the app. About Page text at the bottom:

Rating: <div style="height: 16px; width: 85px; background-image: url(; background-repeat: no-repeat"></div>
Rate this app: <a href="">1 star</a>, <a href="">2 stars</a>, <a href="">3 stars</a>, <a href="">4 stars</a>, <a href="">5 stars</a>

Here's what that looks like when the About Page is shown:

Adding rating to an application's Canvas Page

To add app rating to the Canvas Page of your application (so that users can rate from within the app) you add the following HTML:

<hr />
Rating: <div style="height: 16px; width: 85px; background-image: url(; background-repeat: no-repeat"></div>
Rate this app: <a href="">1 star</a>, <a href="">2 stars</a>, <a href="">3 stars</a>, <a href="">4 stars</a>, <a href="">5 stars</a>

Replacing YOUR_APP_ID with the application ID (i.e. the number on the app's About Page) of your application.

View the top applications

Anyone can view the top applications by clicking this link.

Warning to fraudsters

A note for fraudsters: behind the scenes I'm monitoring how the voting is taking place and where the links are coming from, even how they were inserted. Don't mess with this, or risk having your application blacklisted. It would be a pity if trying to game the system resulted in your application's rating disappearing completely :-)

Labels: ,

Thursday, July 05, 2007

Stop me before I code again: another Facebook application

I woke up with a brainstorm and I just had to implement it. You may remember the Five Things meme that was going around the blogosphere a while back. I thought it would be fun to have something similar on Facebook, but with a little twist: one of the things is a lie.

So, I created the Four Secrets, One Lie application which lets you post five things people don't know about you, one of which is untrue. The application randomizes the order and places them on your Facebook profile page.

To make it interesting for the visitor you can click on each secret to discover whether it's true or not.

Here's my current set of Four Secrets, One Lie:

* John is a qualified SCUBA diver.
* John is a closet Meatloaf fan.
* John plays the drums in French Meatloaf tribute band "Pain de Veau"
* John speaks French very well.
* John thinks Neve Campbell is just perfect.

I have just one more idea for a Facebook application and then I'd better stop coding these things, it's getting addictive.

Labels: ,

Tuesday, July 03, 2007

So, I built a Facebook application: Easter Egg

I've been playing with Facebook for a little over a week and I couldn't resist trying out the Facebook Platform. To be honest despite the missing documentation and changing APIs, they've done a nice job.

My first attempt at an application took a little over 3 hours and is called Easter Egg. It lets you leave Easter Eggs on your profile that only certain visitors can see. So, for example, you could leave a little love note for your girlfriend, or details of a secret party for your buddies, or just say Hi! when your Mom visits. And here's a screen shot:

If you are a Facebook user and like that sort of thing you can add Easter Egg.

Labels: ,

Wednesday, June 20, 2007

jeaig (jgc's email address image generator) launches

Today is launch day for a simple little web site called jgc's email address image generator. It's a web service that enables anyone to generate a CAPTCHA like image containing their email address for insertion on their web site.

Since web crawlers are currently unable to look inside images to scrape email address this means that your email address will not be scraped from a web site, but can be written down by a human.

Here's an example email address:

Made using jeaig

and the code that generates that is:

<img src="
<br />
<font size="-2">Made using <a href="">jeaig</a></font>

The server does not store the email address: when a user enters an email address on the site it is padded with a random amount of random data (both before and after the address) with randomness being supplied by /dev/urandom. Then the address is encrypted using Blowfish using a secret key known only to the jeaig server (this key was also generated from /dev/urandom) and a random IV is chosen.

The encrypted data is then modified base-64 encoded so that it can be used in the URL.

When the image is requested using the special base-64 filename the email address is decrypted and then rendered using CAPTCHA code to produce the image. The image changes each time the email address is loaded.

And, yes, this is a free service.

Labels: ,

Thursday, April 19, 2007

UseTheSource (re-)launches: social code snippet web site

Almost 8 years ago I registered the domain name (as in Use the Source, Luke!) and for a long time ran it as a blog (back when people were first starting to say the word 'weblog'). It even got me an appearance with Leo Laporte on The Screen Savers (if you are old enough to remember that show :-)

Well, UseTheSource is back, but not as a blog, it's back as a Reddit/Digg style social news web site with a twist: it's only intended to accept links to pieces of code. It's unashamedly for programmers who want to see working code.

So if you see a cool hack, a great explanation of an API, an neat algorithm think about submitting it to UseTheSource. You can also submit articles that are relevant to the site, but bear in mind that I'm trying to encourage people to submit things with working code!

The code snippets are categorized by language (I'll add languages on demand), and the site supports Digg-style voting plus user-defined tags. To get things going I've submitted a bunch of suitable items (most from my own writing).

Of course, it's very much in a 'beta' state and I'll be happy to receive feedback on bugs you encounter or suggestions for improvements.


Wednesday, March 28, 2007

Some statistics about usage

A regular user of my service wrote in to ask if I had any statistics about its use. I didn't until I grep/cut/wced a few log files, and now I do. Since its inception:

Unique URLs monitored2,256
Unique email addresses (i.e. # of users)586
URLs that were still down after a week of monitoring205
# of URLs monitored by the most active user763
# of rules used to identify non-working sites67
Total ad revenue$13.37 now uses 67 separate rules to determine whether a site is available or not. That number is growing as is improved. The more users the better it gets.

It's interesting to look at the distribution of 'dead times' (how long a site remained dead from it being reported to for monitoring and then actually being available.

The big initial bar are people who get a response in under 10 minutes; many of those people are no doubt kicking the tires to see if works at all! Once you pass 10 minutes you can see that the average web site comes back on line after 1h45m.


Tuesday, January 09, 2007

Introducing rpnbuddy

rpnbuddy is an AIM bot that implements a reverse polish notation calculator with floating point, fixed decimal places, decimal, binary, hexadecimal and octal modes. It's currently in somewhat beta, but feel free to chat to it using the AIM user name 'rpnbuddy'.

Theoretically, rpnbuddy is online all the time, but if you have trouble accessing it please drop me a line. As usual, rpnbuddy is a totally free service from me; I'll do my best to fix bugs and add features as requested. At this time the source code is not open.

Typing help makes rpnbuddy print out the following help information:

Arithmetic operators: + - * / % (mod)
Bitwise operators: and, xor, not, or
Functions: sqrt, e^x, 10^x, x^y, cos, sin, tan, ln, log, int, abs, x^2, 1/x
Set word size: push word size (8, 16, 32, 64) then wsize
Set base: dec, bin, oct, hex
Set floating point mode: float
Set fixed decimal places: push decimal places (up to 16) then fix
Show stack: stack
Show state: state
Useful constants: pi, e

And here's a the log of an rpnbuddy session calculating the area of a circle of radius 10:

(13:27:31) jgc: pi
(13:27:31) rpnbuddy: 3.14159265358979
(13:27:39) jgc: 10
(13:27:41) jgc: x^2
(13:27:42) rpnbuddy: 100
(13:27:43) jgc: *
(13:27:43) rpnbuddy: 314.159265358979

Or switching to hexadecimal mode you can do a little bitmasking:

(13:28:28) jgc: 0
(13:28:29) jgc: hex
(13:28:30) rpnbuddy: Unsigned; Base: hex; Word size: 32
(13:28:30) rpnbuddy: 00000000
(13:28:38) jgc: 1234abcd
(13:28:42) jgc: fefefefe
(13:28:43) jgc: and
(13:28:43) rpnbuddy: 1234aacc
(13:28:52) jgc: ff
(13:28:53) jgc: xor
(13:28:53) rpnbuddy: 1234aa33



Monday, October 23, 2006 gets an upgrade

My 'tell me later when this web site is available' server got an upgrade today. There are three things that are officially being released:

1. There's a bookmarklet which you can drag and drop to your toolbar. Just monitor a URL with and you'll be offered the bookmark customized to your email address. (Thanks for Iain Wallace for the code).

2. There's a Firefox extension that makes using a breeze. It's on the main page: click it to install it. Once configured with your email address a simply right-click on a link you want to monitor gives the option Monitor with l8tr. Click that and starts monitoring the link. (Thanks to Barrett for the code; he gets the $50 bounty).

3.'s cache is now working. As well as checking to whether a site is available, caches the site's content and offers users both the original URL and the cached version.

In addition much has happened behind the scenes to make sure that site availability is correctly recognized.


Wednesday, October 04, 2006


My latest little venture is a free service called It's for all those times when you want to visit a web page but can't because the web page is running too slowly, or is completely overloaded, or you are in the middle of your work day and the page is NSFW.

Just type in the URL of the web page, and your email address. will check the availability of the web site and once it becomes available you'll receive an email.

That means there's no need to be frustrated when you can't get to a web site. will watch it for you and send you a simple email reminder.


Thursday, September 14, 2006

A C implementation of my simple GPS code

Reader Chris Kuethe wrote in with a version of my simple code for entering latitude and longitude to GPS devices written in C (my demonstration code was in Perl).

Seems Chris is a bit of a GPS fanatic and maintains a page on GPS hackery.

He ported my Perl code to C and is releasing the code freely. He gave me the choice of releasing under two clause BSD license or making it public domain. I think the most generous is public domain (especially since the Perl code was public domain).

Here's the code to compute a SOC:

#include <sys/types.h>
#include <stdio.>

main(int argc, char **argv){
int i, j;
unsigned long long lat, lon, c, p, soc_num;
char soc[11], *alpha = "ABCDEFGHJKLMNPQRTUVWXY0123456789";
int primes[] = { 2, 3, 5, 7, 11, 13, 17, 23, 29, 31, 37 };
float f;

if (argc != 3){
printf("Usage: %s <lat> <lon>\n", argv[0]);

sscanf(argv[1], "%f", &f);
lat = (int)((f + 90.0) * 10000.0);

sscanf(argv[2], "%f", &f);
lon = (int)((f +180.0) * 10000.0);

p = lat * 3600000 + lon;
soc_num = p * 128;

c = 0;
for(i = 0; i < (sizeof(primes)/sizeof(primes[0])); i++){
c += ((p % 32) * primes[i]);
p /= 32;

c %= 127;
soc_num += c;

for(i = 9; i >= 0; i--){
j = soc_num % 32;
soc[i] = alpha[j];
soc_num /= 32;
soc[10] = '\0';

printf("%s\n", soc);

And to compute latitude and longitude from a SOC:

#include <sys/types.h>
#include <stdio.h>

main(int argc, char **argv){
int i, j, c, k;
unsigned long long x, y, p, soc_num;
char soc[11], *alpha = "ABCDEFGHJKLMNPQRTUVWXY0123456789";
int primes[] = { 2, 3, 5, 7, 11, 13, 17, 23, 29, 31, 37 };
float lat, lon;

if ((argc != 2 )|| (strlen(argv[1]) != 10)){
printf("Usage: %s <10-digit-SOC>\n", argv[0]);

soc_num = 0;
for (i = 0; i < 10; i++){
c = (char)argv[1][i];
c = c & 0xff;
c = toupper(c);
case 'I': c = '1'; break;
case 'O': c = '0'; break;
case 'S': c = '5'; break;
case 'Z': c = '2'; break;
default: ;
for (j = 0; j < strlen(alpha); j++)
if (c == alpha[j]){
soc_num = (soc_num * 32 + j);

p = soc_num / 128;
k = soc_num % 128;

lon = ((p % 3600000) / 10000.0) -180.0;
lat = ((p / 3600000) / 10000.0) - 90.0;

c = 0;
for (i = 0; i < (sizeof(primes)/sizeof(primes[0])); i++){
c += ((p % 32) * primes[i]);
p /= 32;

c %= 127;
if (c != k)
printf("warning: checksum mismatch - %d %d\n", c, k);
printf("%0.4f %0.4f\n", lat, lon);

Thanks Chris!

Update: Chris writes to say that B1NLADEN02 can be found in Antarctica: -76.7847/-106.0187 and JIMMYHOFFA is here: -23.3433/-61.6087.


Monday, July 10, 2006

A simple code for entering latitude and longitude to GPS devices

This post proposes a coding system for entering any location on earth with 10m of accuracy using a 10 character code that includes features to prevent errors in entering the code.

The idea is that any one could publish their location by writing something like VUF DDC F8UG. This short code could be entered into a GPS device giving you any spot on the globe.

I'm calling it the SOC: Simple Orientation Code.

Some example uses:
  1. I could print my company's SOC on my business cards and visitors could punch it into their car navigation system and come visit
  2. A restaurant could publish its SOC along with its phone number (after all it's the same length as a phone number so it's something people can easily grok) making the restaurant easy to find
  3. Geocachers could publish SOC trails for people hunting down caches
  4. SCUBA divers could refer to dive sites by their SOC (10m of accuracy is enough surface accuracy for most people)
Here's how the code works.

First you need the latitude and longitude of the location you are talking about to 4 decimal places of accuracy. 4 decimal places gives about 10m of accuracy. So treating latitude as ranging from 0 to 180 degrees (basically change it from -90 to 90 degrees by adding 90) and longitude as from 0 to 360 degrees (ignoring east/west or +/- values) and then treating the two numbers as integers (i.e. take the 4 decimal place latitude or longitude and multiply by 10000) you get two numbers: La and Lo.

La varies from 0 to 1,799,999 and Lo from 0 to 3,599,999. These two numbers can be combined to form a single number that I call P (your position) like this:

P = La * 3600000 + Lo

Extracting the La and Lo from P is simply a matter of dividing P by 3,600,000 (to get La) and calculating the remainder (to get Lo).

P varies from 0 to 6,479,998,200,000 which can be stored in 43 bits.

Now encoding P in some form typeable by a human requires an alphabet. The SOC alphabet consists of the following 32 characters:


This is the standard English alphabet plus Arabic numerals 0 through 9 with the following letters removed: I, O, S, and Z. These are removed because I is easily confused with both 1 and J; O is easily confused with 0; S is easily confused with 5 and Z is easily confused with 2. These characters are removed to ensure that the code is minimally affected by bad handwriting.

Moreover an implementation using the SOC should silently perform the following translations: I becomes 1; O becomes 0; S becomes 5 and Z becomes 2. This way the user will not have to correct a poorly written SOC.

Each character in the alphabet represents a number between 0 and 31.

A(0) B(1) C(2) D(3) E(4) F(5) G(6) H(7) J(8) K(9) L(10) M(11) N(12) P(13)
Q(14) R(15) T(16) U(17) V(18) W(19) X(20) Y(21) 0(22) 1(23) 2(24) 3(25)
4(26) 5(27) 6(28) 7(29) 8(30) 9(31)

P can be encoded using 10 characters from this alphabet. Since each character contains 5 bits of information and only 43 bits are needed for the position that leaves 7 bits for an error checking code. The algorithm used to generate the check digit is a variant of the scheme used for ISBNs.

The 43 bit P is broken into 11 4 bit numbers with a zero padded on the left of P. The 11 numbers are p0 through p10. A check digit C is calculated as follows:

C = ( p0 * 37 + p1 * 31 + p2 * 29 + p3 * 23 + p4 * 17 + p5 * 13 + p6 * 11 + p7 * 7 + p8 * 5 + p9 * 3 + p10 * 2 ) mod 127

C is then appended to P to create the SOC.

Now for some Perl code that implements the coding and encoding of SOCs.

Converting a latitude and longitude to a SOC:

use strict;

if ( $#ARGV != 1 ) {
die "Usage: to-soc ";

my ( $lat, $lon ) = @ARGV;

my $alpha = 'ABCDEFGHJKLMNPQRTUVWXY0123456789';
my @alphabet = split(//,$alpha);

$lat += 90;
$lon += 180;

$lat *= 10000;
$lon *= 10000;

my $p = $lat * 3600000 + $lon;

my $soc_num = $p * 128;

my @primes = ( 2, 3, 5, 7, 11, 13, 17, 23, 29, 31, 37 );

my $c = 0;

foreach my $prime (@primes) {
$c += ($p % 32) * $prime;
$p = int($p / 32);

$c %= 127;

$soc_num += $c;

my $digits = 10;

my $soc = '';

while ( $digits > 0 ) {
my $d = $soc_num % 32;
$soc = $alphabet[$d] . $soc;
$soc_num = int($soc_num/32);

print "$soc\n";

Converting a SOC back to a latitude and longitude:

use strict;

if ( $#ARGV != 0 ) {
die "Usage: from-soc <10-digit-soc>";

my $soc = uc($ARGV[0]);
$soc =~ tr/IOSZ/1052/;

my $alphabet = 'ABCDEFGHJKLMNPQRTUVWXY0123456789';

my $soc_num = 0;

foreach my $letter (split(//, $soc)) {
$soc_num *= 32;
$alphabet =~ /(.*)$letter/;
$soc_num += length($1);

my $p = int($soc_num / 128);
my $check = $soc_num % 128;

my $lon = $p % 3600000;
my $lat = int($p / 3600000);

$lat /= 10000;
$lon /= 10000;

$lat -= 90;
$lon -= 180;

my @primes = ( 2, 3, 5, 7, 11, 13, 17, 23, 29, 31, 37 );

my $c = 0;

foreach my $prime (@primes) {
$c += ($p % 32) * $prime;
$p = int($p / 32);

$c %= 127;

if ( $check != $c ) {
die "Incorrect SOC";
} else {
print "$lat $lon\n";

This idea and code is being released by me into the public domain.

Those of you with a twisted mind like to try to find points on the globe that have human-readable SOCs. For example, by picking coordinates that contain a word in the SOC. Challenge: find a location on the blog that's something along the lines of TREASURE or STARTHERE.