The Time Has Come (the Walrus said) Archives


In a brilliant post, here, Raymond Chen makes a nice point about UNDERSTANDING.

By crikey, I can identify with that. (Work colleagues who might read this – I’m generally not referring to you!).

I used to work years ago with guys writing software, who never really knew what they were doing. Their attitude, and they would say it aloud was “Hmm, that didn’t work. I’ll just TRY THIS.” And then furiously bash away at the keyboard some more. It took enormous will power to stop from bashing their fingers off the keyboard and yelling “stop, think!”. Instead I had to patiently sit with these guys and walk them through a process of stopping, thinking, evaluating, considering, looking at their coding – and only then, changing something in a slow an considered way.

I wanted an old fashioned school teachers yard-stick (metre long ruler, these days), to WHACK THE HANDS of those who rush in where anybody should fear to tread.

Programmers who furiously rush in to change things without thinking give the illusion of being terribly active and busy. Busy without thought does not produce results. Thought, then busy, works better.

The rush to action was, I think, motivated by laziness. However, to think first, and then act is even lazier. Another reason I prefer it.

The ReadyNAS is ready for take off

Just before Christmas I bought a NetGear ReadyNAS Duo.

Wots a ReadyNAS? It’s a thingy you plug onto you local network. If you have an ADSL modem or router, then you have a local network. You just need a spare RJ-45 jack to plug it into.

The ReadyNAS, in its most basic form, just gives you a location you can copy files to with oodles of storage. It can be tizzed up to do all sorts of other things (like serve a blog or a picture gallery out over the internet, without a need to keep a PC running).

$499 from Officeworks is the best price I could find anywhere, it gets a machine with 500 GB of storage and room for a second hard drive. Putting the second drive in does not double the storage, it means you store 2 copies of everything in the ReadyNAS, so that in the event of a single drive failure you have another copy sitting there. You can buy another 500 GB drive for about $100 from most computer shops.

I’ve been worried for some time about the hard drive in the PC dying. Seeing as we have zillions of digital photos, and backup is a pain, then the possibility of a disk failure leading to loss of all our photos is very real. And disks do fail. Back when I was a small network system administrator we used to bet on about 1 disk drive in 30 failing, once a year.

The other neat thing about the ReadyNAS is it comes with a program to automagically copy everything you tell it to onto the ReadyNAS and then monitor your main disk for changes, and copy them as well.

The only trouble is, the program supplied with the ReadyNAS to do this task is, well, not all that flash. It does weird stuff. It misses some files (typically a few hundred in every 30,000 files). It crashes now and again with strange errors. And it’s slow and makes the computer run s..l..o..w.

So, folks, I’ve written a replacement program: QuickShadow.

You can download the installer here:

See my minions oh Brisbane, and tremble

The entire software group from work is in Brisbane for the annual Australian Delphi Users Group symposium.

Somehow we managed to get approval for all of them, so seven travellers are out wreaking havoc. Brisbane will never be the same again.

I notice that MikeFitz must have had advance notice and was so scared he left town :)

I managed to condense the entire 5 page company travel policy into one important bullet point for them before they left: Don’t consume anything from a mini-bar, unless you want to pay for it yourself.

For some bizarre reason the company will pay travel expenses, such as meals and accommodation – but the mini-bar is not included. A room service meal with a beer in the order is fine. Taking the beer from the fridge is not. Go figure that one out.

A software developers lot is not a happy one

Raymond Chen summarises the lot of the software developer so well that I’ll blatantly quote and rip off:

The ironic thing about fixing a bug, or at least once I mention on this web site that I fixed a particular bug, is that people immediately complain that I didn’t fix some other bug. One school of complaint believes that cosmetic bugs should be fixed first: “You suck. I mean, look at these egregious cosmetic bugs. If you can’t get even those right, then obviously you can’t get the other stuff right either.” The opposite school believes that cosmetic bugs should be fixed last: “You suck. I mean, why are you fixing cosmetic bugs when there are these other bugs!”

But at least both camps agree on one thing: I suck.I think I’d be better off if I said I didn’t fix any bugs at all.

Defect Storm!

Today at work we took the programmers to a far distant part of the site, into a separate room, laptops, PC’s, test gear, and ran DEFECT STORM. Dunno quite where the idea sprang from or why I canned it that… but…

The idea was to trawl through about 2-3 years worth of boring low grade crap software defects that have been reported but we’ve never done anything about them – because there have been more pressing things to do.

The general rule of thumb was that if a defect would take more than 1/2 hr to fix, and verify, then do it some other time.

It’s been a full on day: with 4 developers going flat out, a software leader / co-ordinator trawling the lists, and 2 managers checking fixes, finalising the clerical work, fetching lunch and chocolates for the happy workers.

The guys fixed 66 defects involving things like placement of labels & boxes on forms, spelling errors, and a few minor functional things (like “why does this beep when I do blah blah”). Thats 66 fixed, and verified.

At the same time we’ve reviewed the outstanding lists, found things that are just obsolete (sorted a long time ago but not recorded as such), found defect reports that are duplicated, and so on. All in all we have been able to close over 130 reports in a day, and have reviewed 50% of the reports that have been made.

Now that the low hanging fruit has been picked, its back to the grindstone of the more tricky ones – but everybody seemed to think it was a worthwhile exercise.

Final tally for the day:

5 Pizzas (12 inch)
10 litres of coke / coke-zero
0.5 litres of water
Approx 1 kg of chocolate (TV mix, Fruchocs, etc)
1 LARGE bag of Minties (cos you need em at times like this)
66 defects actively worked on and corrected
130 defects closed

Whew! What a day. Everybody did a champion job!

Neat free software

Check out autostitch… for those who take panorana photos and want to join the mess back together again:


My employer is looking for a software developer.

We develop in Borland Delphi, for windows / PC, though Delphi experience is not a prerequisite.

We’re looking for somebody who knows a bit more than the superficial stuff about programming, but actually knows what bits and bytes are, and has a bit of knowledge about (or at least an interest in) embedded systems.

We offer a pretty good development environment – in reasonable surroundings (admittedly based in a fairly industrial area). We are ISO 9001 accredited and whilst that imposes some processes on what we do, we are not overly restrictive about the “procedure police”.

We make use of modern software change control systems – in our case we use Rational ClearCase. We also use a defect tracking system and expect everybody to use it, and stick to it.

We test carefully, and aggressively, and occasionally expediently. We try to do about 3 to 5 releases a year – which is a lot, and it keeps us on our toes.

The recruit would join a group of 4 other software developers and work with them on enhancements to existing software, development of new software as requirements come up, as well as general helping out, fixing defects and other things like that.

The position is located in Adelaide, a mere 5 minutes from the CBD.

What we really want:

- A passion for software.

- A good sense of humour to blend in with the other ratbags.

- Some prior experience is desirable – preferably in Java, C++ or Delphi. We aren’t ruling out graduates (but a graduate showing they have done some software development or something, for someone, in some capacity over and above studies will sure go down well.)

- An ability to communicate – both speaking and in writing. We don’t want Shakespeare, but an ability to explain yourself is essential.

So, if any of the 2 readers out there either fit the bill, and are looking for a job – OR if you know somebody who might be interested, please email me – the contact details are over on the right hand side panel…. A confidential chat can be arranged either during working hours or in the evenings.

Oh… and if you email… please attach a CV…

Hooray for women with brains

I’ve spent today working from home, trying to solve a particularly thorny technical problem.

If it works it will deliver a significant improvement in capability and features for one of the products made at Clipsal.

I spent most of the day poking around in the murkier depths of hash functions… not making a lot of progress but with some ideas that had merit.

SWMBO interrupted me for an afternoon tea break, so I explained the problem I was trying to solve. She promptly suggested a couple of things I’d not even considered… 2 more hours thinking about it and hashing is out the window… a much simpler approach now.

Thanks t’other half – I’d have spent a long time getting nowhere without your ideas to drive me in significantly different direction – simpler, and much more likely to do what’s needed!


There are some benefits when the wife / partner / whatever has a similar education and has worked in related fields – its very easy to get into a technical discussion (at home!) that leads to all manner of new ideas… But now she wants to go on the payroll. That might be a more difficult ask.

Code like a girl

In my endless references to “Creating Passionate Users“, another great article has turned up.

This time “Code Like a Girl” – code that’s been polished and well crafted gives a satisfaction to the author, and is a pleasure for others to use and maintain:

…caring about things like beauty makes us better programmers and engineers. We make better things. Things that aren’t just functional, but easy to read, elegantly maintainable, easier–and more joyful–to use, and sometimes flat-out sexy. A passion for aesthetics can mean the difference between code that others enjoy working on vs. code that’s stressful to look at..

This fits so well with my attitude to writing code. When going back over code I’ve written for some reason, I’ll polish – if only the formatting and layout: find the violations of the coding standards and fix them, correct the spelling errors, look at the comments and figure they are crap – and re-write them.

For me, nice code should be easy to understand and maintain. It’s like a work of art. It not only works right, it’s a pleasure to look at for the next geek who has to maintain it.

Feature demands in software

Nice article about feature demands in software.

Interesting point about trying to win over the haters. Don’t bother, they hate you and your product!

Mr Paperclip we hate you

Found this by accident.

I don’t know anybody who likes the Microsoft painful pop-up paperclip that wants to help me. Even my 12 year old son can’t stand it.

This little video clip sums up my reaction very well. *Not safe for work – uses the F word*

Mr Clippy and his pals are really good examples of software that tries to be too clever and gets in the way. We need help systems that let us solve a problem, when we have a problem, and only when we have the problem. Gratuitously popping up and disrupting us is just plain rude.

Letting your users kick ARSE

Kathy Sierra has written a marvellous article about software (or products) and features, why some succeed and some fail, and why we should do some developments and not others.

Critical questions we should be asking in product design are “Why are we doing this” and “What will our users get from this?”.

If the answer is not “so our users can kick ass” (OK, she’s American, they don’t know it should be arse) then you have to question why you are doing it.

Now that I think about it, where I work most of the things we put into the products we design, have this as an ultimate reason. The method of “kicking arse” varies of course…

Why are we adding some of the current crop of features to our software?

So our customer can commission a site faster. (And do more jobs & make more profit, or bid cheaper, or go home earlier to see his/her family).

Why did we add some new features to some of the hardware / firmware products we sell?

So our customer can offer something that looks nicer to a home owner – less wall-acne. (The home owner has less unsightly gunge to look at every day.)

I’m pretty happy after reading this article that the approach we are taking for product development is generally heading the right way… very little we do is for its own sake… most is based around getting a sensible answer to the question “what benefit will our customers and users get from this?”. It’s not quite so hard-hitting as “so xxx can kick arse”, but the principle is pointing in much the same direction.

Features in products

Another one from Kathy Sierra. Needs no further explanation, just read it here.

The most common-sense (and hopefully influential) writers about software and product design, in no particular order:

(classic authors)
Tom DeMarco
Tim Lister
Fred P Brooks

(more recent authors)
Joel Spolsky
Kathy Sierra

Sit up and pay attention folks, hunt these authors down and read what they have learnt from their own schools of hard knocks.

Backup your PC!!!

Earlier in the week I was doing some very demanding stuff on the home PC, so I went out and bought some more RAM for it. This would give me a 1 GB pig pen for all the software to play in.


After fitting the new RAM I had a series of crashes, resulting in some pretty serious corruption of the hard drive.

After a fruitless night spent trying to get it working, I gave up and reverted to the backup.

My backup is a 100% image of the main disk, so out with the screwdriver and 3/4 hour spent swapping hard drives had me back in business, though with 6 weeks data lost.

Now I’m picking through the corrupted drive selectively trying to pull back that missing 6 weeks….

And later I have to try and find which module is busted, and then go fight with the shop I bought it from…



(Note: This advice is not good enough for a corporate PC)


Most backup programs and processes for home PC’s SUCK big time. They only do a portion of your disk – maybe your user files. Very few do your registry entries, and even fewer do all the installed programs. Even those that do, tend to do so badly or incompletely, or assume you do not suffer a total loss.

If you ever have to restore based on your hazy memory of all that stuff you’ve downloaded and installed over the years, you’d know how hit and miss this can be.

I STRONGLY recommend everybody do what I do:

Buy an external USB 2 drive case (about $50 to $100 – eBay can be a bit hit and miss). Do NOT buy one with a drive in it.

Next, buy an IDENTICAL drive (same manufacturer and model number) drive to what you run in your PC, and put that into your external drive case.

(At this step, you may not be able to buy what you already use if it is a bit on the old side. In that case you have a much more complex job requiring purchase of 2 new drives, and a complex migration process to get everything onto the new bigger drive, and to get that installed…)

Then, use software like Paragon Drive Copy (which I was able to get as a free download) to periodically make a 100% duplicate of your entire main drive to your USB drive.

Do this about every 4 weeks.

It will take a while – duplicating my 80 GB drive takes about 1.5 hours. Live with it.


Backup up important data (like digital photos, letters, important downloads, etc) to other media, like a rewritable CD or DVD.

Try and do this WEEKLY.

This backup won’t wave you from every ill… If you end up with data corruption of any kind you will just duplicate it – so check you main drive for errors now and again.

What this backup process does, though, is to save you from much pain and suffering in the event of a total loss.


I’ve been doing this from paranoia on 2 PC’s for the last 12-18 months, and now it has literally saved me. Only trouble is, I was not paranoid enough and did not do the full backup frequently enough.

6 weeks of lost info includes a lot of digital photos, a whole stack of SWMBO’s study material, tax records, home budgeting, and more. It looks like I’ll be able to get about 95% of this back from the stuffed drive, so I have been lucky.


Paragon drive copy does not work for me because I have 4 main hard drive partitions with different file systems, for booting Windows XP as well as Linux. Paragon drive copy barfs for some reason when copying some of the Linux stuff (it is meant to work, but fails).

Here is the happy hackers way to do a 100% copy if you have Linux (ideal for a micro-linux booting off a Flash drive or separate hard drive partition):

1. Boot into Linux, in single user mode. Make sure your USB hot-plug support is running (it is by default on most). To boot in single user mode, you need to put the word “single” without the quotes onto your boot line. If using GRUB to boot, use the “e” key to edit the boot line.

2. ASSUMING your main hard drive is hda, and your usb drive is sda, then enter the command (change as appropriate if your devices are called different things):

dd if=/dev/hda of=/dev/sda bs=100M

3. Wait for this command to complete – it will take a while – bigger drives take longer – 80GB will be 1-2 hours.

4. Shutdown linux (use the halt command).

5. Unplug your USB hard drive and lock it up somewhere secure.

The “dd” command above is used to copy pretty much anything to anything. It’s been in unix for a long time (I don’t know what “dd” stands for – it seems awfully similar to the old IBM MVS JCL “DD” statement….)

The command copies from the input file (”if=”) which specifies the entire device “hda”, to the output file (”of=”), which is the entire target drive. The “bs” parameter tell it the block size to use, in this case 100 MB. This reduces the amount of IO needed and speeds up the copy process a bit. This number does not matter very much, just make sure it is less than about 1/2 the amount of physical RAM you have. On a modern PC I suggest this should be at least 1MB, and preferably quite a bit more. Don’t use really small numbers or the backup will take forever.

This copy does the entire drive, including boot sectors, partition tables, data, the lot. It is basically a raw copy, byte for byte.

Works a treat for me!

More b*&^$% Windows Software

I’m working from home, doing a very high priority job for work.

In doing so, I’m pushing the old home PC pretty hard… But it is a fairly new, flash one, so it should be up to the task.

It’s much the same spec as the one I use at work, but for some reason it seems to be much slower. I’ve just had serious BSOD crash, which the magic Microsoft crash analyser tells me was in “iomdisk.sys”.

This turns out to be a driver that is part of the IOMega Active Disk program. I don’t even know how Active Disk ended up being installed here.

But I have now uninstalled it, and guess what – EVERYTHING seems to be running a lot faster.

Windows Software ARRGGGHHH

I’m having a bad day.

I’ve been working from home, and my home PC is crashing – just every now and again. I must admit I’m hammering it hard. When it stops, its not a BSOD, its a complete reboot without warning.

Turns out there are some OLD dodgy drivers that seem to be the culprit.

Which brings me to the important point:

When I remove something from a Windows machine, I get REALLY pissed off with DUMB software makers who cannot or will not COMPLETELY remove their software.

That means:

- EVERYTHING related to it under “Program Files”

- EVERY registry entry

- EVERY device driver

Any vendor who does not do a decent clean up of their own droppings is derelict in their duty!!!

I’ve just spent a painful hour removing old crap drivers and registry muck from hardware I pulled out 18 months ago (or in some cases never even installed). I *hope* this will make it more stable. If not, a complete re-install might be coming up.

And, BTW, this is XP SP2, which I had otherwise though was pretty stable.

Not happy, Jan.

Prioritising Product Development

Joel Spolsky sent the latest essay about prioritising product development, specifically regarding software.

I think it applies more generally.

It will take 10 minutes, but this is essential reading for anybody doing product development. You can find the article here. Take the effort to read it.


I’ve found a free emulator for windows and linux which does the same job as VMWare: Qemu. This is not as fast as VMWare, but hey – its free.

VMWare and Qemu are very useful as a means of building a quarantined test environment – allowing you to run another operating system in a window.

So far I have XP running inside a Qemu VM (on top of XP), and also Fedora Core 4, and I’m just installing Solaris 10 to evaluate for a little server job I might need to set up in the next few months.

Best performance is obtained using the Qemu kernel virtualiser (kqemu) – under windows this needs to be started separately as a service each time which is a bit of a pain. On my 2.4 GHz P4, I get performance roughly the same as about a 500 MHz P4 – maybe a bit better. It would be even better if I had more memory.

You can find Qemu here.

Dumb computer security

Thanks Bruce Schneier…

There was a reference in the latest crypto-gram to this article about the top 5 dumb things in computer security.

I especially like #6 about inaction and action, and this:

It is often easier to not do something dumb than it is to do something smart.

Hitting the high notes

For those who have not heard of, or read, the essays of Joel Spolsky on software development – you should. 9 out of 10 times this guy is bang-on.

The latest is about hiring (a small number of) the best programmers (as opposed to a large number of mediocre).

Compulsory reading here.

Now, if only some management would read this and actually take the time to understand it.

Programming in Delphi

I’ve spent most of the weekend modifying a program written in Delphi. This program is something we use at Clipsal Integrated Systems, as part of the support of the C-Bus system.

We need to have some enhancements done very urgently so we can supply the program to a contractor who is developing a new product for us. These changes were started by somebody else, but for various reasons were not finished in time. So, there was no choice but to leap in and finish it off.

Delphi is PASCAL on steroids – add all the graphical stuff, wonderful conversion libraries, exceptions, classes, etc etc.

The last serious PASCAL programming I did was back in about 1988, and I have never programmed in Delphi before. I had a crash course in installing components on Friday afternoon.

Now, after about 2 hours to get used to how things work, and for all my PASCAL to come back to the top of my memory – I’m very impressed. Delphi does make graphical UI programming nice.

Now to finish the changes off so I can deliver the updated program on Monday morning.

New book I’ve got to get

Looks like I’ll be out hunting for this new book edited by Joel Spolsky. The titles of the chapters / articles are enough to prick my interest.


It’s been a fun day. There is a long story – not repeated here, that resulted in the need to generate a financial report for an organisation the other half is involved with.

We managed to extract the relevant data from the package that is used [which cannot generate the reports - it isn't flexible enough], and import it into MS Access.

Then, using a combination of the bits I knew about Access, and the SQL that SWMBO* knows from a past life as a database administrator we were able to do a bunch of queries, generate strange measures, do various accumulations and totals and so on. Report done & faxed off, very spiffy looking.

I must admit to being impressed. SQL has always been a mystery to me, so to see somebody enter it and get it to do something useful has been a bit of an eye-opener.

*She Who Must Be Obeyed

Wordpress Theme

Finally found a WordPress Theme I like – this one is CleanBreeze.

I’ve tinkered with it a bit to make the text larger (I needed a microscope before).

You can get CleanBreeze here.

What I like:
. Fairly clean without fluffy frilly bits
. Post headings stand out enough for you to find them
. Post dates are actually in a sensible format

What I don’t like:
. Text was too small (tinkered with that and fixed it)
. Not wide enough on the page (will fix that with a bit more time and fiddling

Personal Finance Software

I use a well-known big-name Personal Financial software package to track a few the household expenditure which includes a few small shareholdings, thereby hangs a tale…

In Australia, companies can pay Franked Dividends.

When the statement arrives you get three numbers on it:

- the first number is the Franked Amount. This is the amount of cash you get, on which the company has paid tax.

- the second number is the Unfranked Amount. This is the amount of cash you get, on which the company HAS NOT paid tax.

- the third number is the Franking Credit, sometimes called the Imputation Credit.

Most companies pay Franked Dividends which makes the discussion that follows a little easier to follow – ignore the Unfranked Dividends.

The treatment of these numbers is important for tax purposes. There is an important principle here of avoiding double taxation. The Franked Amount represents a payment after company tax has been paid, and the amount of company tax that was paid is the Franking Credit.


If your personal income tax rate is the same as the company tax rate, there is no more tax to pay.

If your personal income tax rate is less than the company tax rate, it means that too much tax has been paid, and you get some back from the tax office.

If your personal income tax rate is more than the company tax rate, it means that you need to pay a bit more.

Here is a practical example. Suppose a company has a profit of $100, and they pay tax at the company tax rate of 30%. This means they pay $30 in tax, and that leaves $70 for you.

Your dividend statement shows a cash payment of $70, and a franking credit of $30.

Suppose my personal income tax rate is 20%. This means the amount of tax I should pay on the earnings of the company (in my hands) is only $20. Seeing as $30 was paid in tax before I got my hands on it, the tax office owes me $10. That is why it is important to record and enter the franking credits on your tax return.

Suppose my personal income tax rate is 40%. This means the amount of tax I should pay on the earnings of the company (in my hands) is $40. Seeing as $30 was paid in tax before I got my hands on it, I owe the tax office $10.

The way the tax office work out what you need to pay (or they pay to you) is easy:

Step 1: Add the franked amount and the franking credit, and add these to your other income sources.

Step 2: Work out the amount of tax your have to pay based on the sliding scale (this means it works out the amount of tax to be paid on the earnings of the company, in your hands.)

Step 3: Give you a credit for the Franked Amount.

Using the above example, add $70 and $30, gives $100 (the earnings of the company, in my hands). Based on my tax rate, work out that the tax on the $100 is (say) $20. Levy that tax against me. (I owe $20.) Now give me a credit for the tax that was paid ($30). Result: tax office owes me $10.

So far this is all lovely, the tax forms and guide make it all clear.

Now… when I use the big name Personal Financial package it does something really dumb.

This program works on the idea of transactions, and categories for each transaction. It is not an accounting package, though it has a few similarities.

The package sold in Australia is an Australianised version that has been adapted from an American package (and that is the cause of its fatal flaw – they do not have Franked Dividends in America).

When I enter a Franked Dividend into the packageit ADDS the Franked Amount and the Franking Credit, and enters that as an earning amount, into a category called “Franked Dividends” (blarp – wrong – it should be called something else!!).

It then enters a second transaction, being the Franking Credit, as an expense amount, into a category called “Franking Credits”.

These two transactions are its means of capturing the two amounts into two categories – but notice that the earnings amount has the Franking Credits ADDED on…

When you generate a tax report to take to your accountant or to use yourself, it just totals up the figures in the categories.

So… using the example above, the package tells you that you have a Franked amount of $100, and a Franking Credit of $30.

What does any normal person do…

They enter Franked Amount $100, Franking Credit $30 into their tax return (even though they only received $70!!!).

Using the example above of the 20% tax rate, this means that the tax office calculates the income as $100 + $30 (=$130). Tax payable on $130 at 20% = $26. Tax paid = $30. Refund from tax office = $4.

You can see that this package, by presenting misleading figures in its reports, leads to people innocently paying more tax than they should. You only find this by manually adding up your statements at tax time to check that the package has done it right…. but nobody does that, because we trust the computer.

How many people are paying too much tax because of this stuff-up

Seeing as there is only an install guide and a CD in the box when you buy it, isn’t it time for the manufacturers to write to all registered users, and tell them how to use the package?

How many taxpayers need to lodge amended returns?

Spell checker for Firefox

I’ve found a fantastic add-on for the Firefox browser. It is a spell checker, which adds a right-click menu option.

You can use this in any text entry panel, it supports multiple languages (there are some huge number of dictionaries available for it), the installation is dead easy, it allows your own custom word dictionaries.

What a great little piece of software. What’s more – no more spelling mistakes in these posts!

You can find it here: Spellbound.

To install – follow the instructions about opening Firefox up for web sites to install extensions, then click the installation link on the main page (above).

Then you need to install a dictionary – that was easy also, and finally to activate it just shut Firefox down and start it again. No Windows reboots!

And it’s free!

Very impressed.

Making wrong code look wrong

If you are a programmer, read this by Joel Spolsky.

Read everything else on his archive as well. There are loads of interesting and useful ideas there.

Powered by WordPress 2.8    Rendered in 23 queries and 0.344 seconds.    CleanBreeze Theme