subscribe secretGeek RSS secretGeek .:dot Nuts about dot Net:.  

Q: Where am I?

A: You're sitting at a computer, reading Leon Bambrick's personal thoughts on programming.

Thu, 23 May 2013 10:58:40 GMT

NimbleText 2.0: More Than Twice The Price!

The latest release of NimbleText is a major milestone, took a lot of work, many bus trips.

As a user of the product, I feel it's good now. I don't want to say it's complete -- because I know how big the backlog still is -- but there's a sort of completeness to it. If no more features were added for a while, I think that would be okay.

I added custom sorting features, and auto preview, and more documentation, and a bunch of other stuff.

I even wrote one of those feature checklists you see in all the expensive professional software suites. --->

Now that's pretty bloody serious stuff.

But then I did something really serious:

I more than doubled the price.

Everywhere I looked, people were telling me to put up the price.

This article crossed my desk today: An eBook pricing model that resulted in $100,000 in sales and contains this quote:

I consulted Patrick McKenzie. Can you guess what he said?

"Charge more."

Of course Patrick would say that.

But when I stumbled onto this article, also just today, 'four pricing principles to never forget' -- the following ALL CAPS headline was like a slap across the face:

CHARGE MORE THAN YOU'RE COMFORTABLE WITH

That was it! Enough was enough. I shut the browser! Slam! Opened the html editor! Whoosh! A search, a replace-all, and it was done in less than a minute.

The price went from $9.95 to $19.95. Double! DOUBLE! Plus five cents!

And I don't regret it for a second. At $20 it's still a steal. I'm seriously thinking of going to $50. Who knows where this madness will end? $75? $78.50?

I have unleashed a pricing monster!


Further reading:

  1. Product Pricing Primer -- Eric Sink.
  2. Money Buys Happiness and You Can Never Have Too Much, New Research Says

Oh, and you'd be wise to get in on TimeSnapper before this pricing madness spreads.

Read On...


Mon, 06 May 2013 12:46:15 GMT

A Computer Simulation of Creative Work, or 'How To Get Nothing Done'

Every year is getting shorter, never seem to find the time
Plans that either come to naught or half a page of scribbled lines

According to the available data, I'm a hard-working and creative person. Yet my productive output tends to hover just above nil. My feelings are generally in line with Roger Water's lyric, quoted above. Why? What causes the gap between work and productivity? But more importantly: can a computer simulation shed light on the underlying problem?

I set about modelling my personal productivity, with javascript and flot.

Here's how the model works:

Every bus trip I work and work and work, always on what is the most pertinent task for the project I am working on.

But as I work, I sometimes think of new projects. I immediately (and at no cost) add those projects to my backlog, then continue with my current task.

As soon as I finish a task, I look over my set of all next actions and choose whichever one feels most interesting at that point in time (modelled as a random selection)

You can play with this simulation yourself:


Creative Dilligence Simulator


The parameters are configurable. By default each project contains 10 tasks (these are mini-projects really). And each time I do a task there is a 25% chance I'll think of a new project.

The results of the simulation are woeful!

Here's an example:

After a year of bus trips, I've done enough hard work that I could've completed 20 projects. Instead I've only finished only 2 (emphasized by the green arrow). Re-running it, I sometimes complete as many as 3 or as little as 0. Meanwhile my backlog of work is big enough to keep me busy for years to come.

As simplistic as the model is, it already makes me feel uncomfortable with its home truths. I know this feeling all too well. Hard work, but it's like spinning your wheels while stuck in mud. I know that my time is spent always on tasks I consider worthwhile, yet I'm still getting nothing done.

Here's the shocking thing. This low productivity is not caused by all the usual culprits we list when discussing 'procrastination'. This isn't because of low motivation or excessive distraction. This isn't because of fear (the alleged mind killer) -- it's not fear of shipping, fear of criticism, fear of success, or any other paralysing phobia.

Getting 'Things' Done versus Getting 'Projects' Done

This is the difference between utilization and productivity. High utilization can be just busy work.

This is purely organisational pathology, and 100% curable.

The immediate question is what to do about it. Now the modelling becomes fun.

If I can decrease my ability to think of new projects, down to around 10 percent (approximately 1 new project idea for 10 tasks done), then I manage to ship more projects.

At the end of the year I've now completed between 8 and 20 projects. Yay. But now a new problem arises: I frequently run out of work to do. Many bus trips I just sit there, twiddling my thumbs, staring out the window. For me, that's a terrifying prospect, a sort of waking death. But in any case, I think it's outside my control. This continual thinking up of new projects (albeit stupid STUPID projects) is just a fact of life. You might as well ask a cat to stop following a laser pointer.

The trick instead is to come up with a new strategy for picking tasks. When I finish one task and it's time to move onto another, I need to be far more careful about which task I work on next.

So I implemented a strategy called 'stick to a project'. In this strategy, I keep working on my current project until that project is done. The results are much more satisfying. I still end up with a giant backlog of work -- but the amount of projects that I've shipped is now exactly in line with the effort I've put in.



That's all I needed to get out of the model -- and at this point I can stop modelling and return to doing.

But it's also just the tip of what the model shows you. Different people have different fears and different desires. Depending on your personal preferences different results are optimal. You might be driven by any of these:

  • Fear of drowning in work (minimize backlog)
  • Fear of running out of work (maximize backlog)
  • Love of a big backlog (maximize backlog)
  • Hate working on the same thing all the time (continual switching)
  • Fear of negative feedback after releasing work (minimize project completion)
  • Desire to release work constantly (maximize project completion)

Play with the numbers, you'll see how to get what you want. Or copy the code and change the model to reflect your own behaviour.

That link again:

Creative Dilligence Simulator


Models are not reality

In practice, things get a lot messier. Projects have variable sizes. Projects grow as you work on them. Some projects *should* be abandoned, not stuck to. (If a job's not worth doing, it's not worth doing properly).

The model is very simple but it was complex enough to demonstrate something useful to me, so I'm happy to publish this as is.

Now I must get back to the gormless and unstoppable implementation of whatever addle-brained scheme has floated to the top of my steaming heap of incomplete mini-projects. Wish me well.

Read On...


Sat, 20 Apr 2013 00:47:27 GMT

NimbleText 1.9 -- BoomTown!

I put out a new NimbleText a few days ago.

The release notes are here, but do you want the minutely-detailed and wildly self-indulgent story behind the release notes? Of course you do!

Along with a spattering of smaller improvements, the main innovation is that you can now expose your settings (and quickly change them) from the toolbar.

I wanted this for a while, but couldn't find the right way to let the user configure it. Finally, with inspiration from Windows 7, I came up with using a pin/unpin metaphor, inside the Options form, like so:

Coming up with this design was surprisingly difficult. Some of the designs I rejected were:

Some people asked for a "view" menu where you check or uncheck the options you want to have appear on the toolbar. Here's a quick mockup:

This concept was broken for two reasons.

First, it looks like you're turning the option itself on or off -- not turning on whether or not the option is shown in the toolbar.

Second, if you were to click one of those menu items, thus toggling its checked state, this would also have the undesirable side effect of closing the menu. So if you wanted to show or hide three settings you'd need to re-open the menu three times, for a total of six-clicks. Annoying behavior! (Incidentally my NextAction tool suffers this problem, embedding so many settings in deeply-nested context menus that collapse whenever you click them. Overriding this behaviour is problematic!)

So the new plan was to put checkboxes of some sort inside the Options form, adjacent to each option. But take a look at this mockup:

Again it's easy to think that clicking the new checkbox will cause the option to be turned on. I wasn't going to implement this or anything like it. Then I noticed the way application icon pinning works in Windows, from 7 onwards.

It's an elegant solution, maybe the nicest touch in Windows since they shot the dog.

So I had my big-chief-graphic-design-intern (i.e. Me) whip out a dodgy mockup, ran it over to my main opinion-deflection-test-subject (i.e. Rhys) and after a few short bursts of shouting the project was green-lighted and implementation began.

Here's the mockup with which I got approval from the board:

If it seems weird to agonize over a small feature like this, I could point out not only a long history of such behavior from myself, but also I can provide evidence that i'm a bit of a toolbar fetishist, having written 6 articles on the topic previously:

What UX have you agonised over lately?

Read On...


Mon, 15 Apr 2013 10:39:23 GMT

Line Endings.

3 people arguing over line endings.

I had a lengthy article here -- browsers, typewriters, javascript blah blah blah, cultural tolerance to backward incompatability in Mac and Microsoft worlds, blah blah blah -- but really, the Hanselman pretty much beat me to it, and all I've got left is a cartoon.

((As a derivative of a GPL'd work ("Tabs."|"Spaces."|"Both."),) The above image is licensed to you under version 2 of the GNU General Public License.)

Read On...


Sat, 16 Mar 2013 00:24:49 GMT

**This** is how you pivot

Startups love to talk about 'Pivoting' -- those sudden changes in strategy, right angle turns that take you from obscurity to success.

"Burbn" pivoted from a location-checkin app to a stylized photo sharing app and became billion-dollar company, Instagram!

Doug and Dinsdale Piranha

But to find the masters of pivoting, we need look no further than the monty python sketch, the piranha brothers. This is pivoting done *right*!

At the age of fifteen Doug and Dinsdale started attending the Ernest Pythagoras Primary School in Clerkenwell. When the Piranhas left school they were called up but were found by an Army Board to be too unstable even for National Service. Denied the opportunity to use their talents in the service of their country, they began to operate what they called 'The Operation'. They would select a victim and then threaten to beat him up if he paid the so-called protection money.

This must not have been a particularly succesful strategem, for we are about to learn that the Piranha Brothers chose to 'pivot'.

Four months later they started another operation which the called 'The Other Operation'. In this racket they selected another victim and threatened not to beat him up if he didn't pay them.

This strategy also met with limited success and another pivot was in order.

One month later they hit upon 'The Other Other Operation'. In this the victim was threatened that if he didn't pay them, they would beat him up.

This for the Piranha brothers was the turning point.

Read On...


Thu, 07 Mar 2013 10:52:31 GMT

Art of the command-line helper

The scariest code I ever wrote is the dialog in NimbleText that helps you use the command-line.

Much smack has been written in the past about confusing command-line helpers in other apps, so I set out to build this dialog with great trepidation in my heart.

Joseph Cooney has laid into two particular apps, a gui for wget, and a gui for robocopy. Even Jeff Atwood had a stab at wGetGui.

Here's what they looked like:

gui for wGet gui for robocopy

And here's a typical user response upon first encountering such a command-line helper:

I downloaded both these apps and tried them out.

Okay, the kindest thing you can say is that they are comprehensive, and with their use of tooltip text they do offer a little more help than the screenshots would suggest.

But they still give an immediate slap in the face to the end user. Something I want to steer away from.

So command-line helpers are a challenge. And to increase the pressure a little more: the command-line feature in NimbleText is only unlocked if you buy a license. If I'm expecting this feature to be worth money, they I really have to not screw it up.

What I did.

The first thing was to use descriptive labels, instead of verbatim option names. Instead of having a checkbox named "--rawdata" I'd have a label that said "Raw data". While this is only marginally more readable, it hopefully decreases the effect shown above.

Next I added a textbox at the foot of the form, where the command-line you've created is written, live, so you can see the output of your furious clicking.

There's a button for save, so you can save your command-line straight to a batch file. (It works from powershell too). A copy button, to put the command-line into your clipboard, and an execute button, which launches a cmd.exe process, and tries out the command-line immediately.

Other than that, I just sweated the small stuff. Alignment, spacing, capitalization, tab order, tool tips, everything as consistent as possible.

What I probably failed to do was give The Dialog any breathing space.

(And looking at the screenshot now I see a slight inconsistency with spacing, which should be fixed by the time you look at the application itself.)

Here's what I came up with:

Any suggested improvements? Please send them in.

Read On...


Thu, 28 Feb 2013 10:57:34 GMT

Go and read a book.

I tweeted this yesterday, but wanted to discuss it in a little more than 140 chars

"Reading a book" is a classic important but non-urgent task. When your lifestyle lacks any book time, you know you're in the wrong quadrant.

Merril Covey Matrix

This is a reference to the four quadrants matrix (urgency versus importance) from the book 'First Things First' by Stephen Covey et al.

The idea is that many of the things we do can be ranked as either important or unimportant, and as urgent or non-urgent.

It's a neat and enlightening concept, but there's something utterly impractical about it.

A response from Dan Puzey summed it up well:

The real problem is that "organizing my life into quadrants" always seems a non-important non-urgent task...

Maybe that's why I've always felt uneasy about the four quadrants idea.

Don't spend time categorizing everything into one quadrant or the other. Don't get caught up in grandiose and abstract questions like "Do I have my life values in order? Am I doing first things first every day?"

Just ask yourself the simple, practical question "Have I read any good1 books lately?"

Your answer sums up a hell of a lot about how you're life is going. If you find you're not reading any good books, then you know right away that your life is out of balance.

Now stop staring at your navel, and go read Slaughterhouse-Five.


  1. If all you've read lately are comic books, by the way, then the answer to the question is an emphatic 'No'.


Image from Wikipedia: Merrill Covey Matrix

Bonus unrelated wikipedia link: Four-Quadrant movie.

Read On...


Sun, 24 Feb 2013 11:35:41 GMT

Slurp up mega-traffic by writing scalable, timeless search-bait

In which I follow the advice of Patrick McKenzie to try and get my little software products into the eyeballs of a whole new audience.

sunday night blues, micro-Isv style

So, it was one of those lazy Sunday evenings when a microIsv guy does what he does best: he looks through the Google Analytics of his products, desperately trying to work out why he is not yet a millionaire, desperately trying to find what tiny tweak he can apply that will ensure he has no need to head to work in the morning, or ever again. (This is known as 'Sunday evening blues, microIsv-style')

When I looked at the search traffic for both sites (TimeSnapper and NextAction), something leapt out at me, the way a tiger in the wilds of India might jump out at a plump looking passerby.

The only search terms people were using to find TimeSnapper were terms like "TimeSnapper", "Time Snapper" or related mis-spellings of the product name.

Noticeably absent from the keyword traffic was every single person in the world who hadn't already heard of the product from some other source. No one looking for "I just lost all my work, how do I get it back?" or "How do I make timesheets easier?" or "How can I understand my own bad habits?" or "Continuous Screenshot Taking" and so on for a million other search terms. (Hint: I just demonstrated the SEO technique of google-bombing oneself ;-) ). So my website -- That Dilligent Little 24 Hours a Day 7 Days a Week Sales Guy, wasn't drumming up one iota of new sales.

And the same for NimbleText. A tiny trickle of people would turn up, but only via search terms like "NimbleText", "Nimble Text" or "World's Simplest Code Generator" (the product's original name) -- and no one else.

So I asked myself, as I sat there on that uneventful Sunday eve: How do I make it happen?

In times like this, I always turn to the writings of Patrick Mckenzie (aka Patio11 on twitter and Hacker News). For SEO he recommends writing 'evergreen' and 'scalable' content.

'Evergreen' content is timeless content: stuff that isn't dependent on today's news cycle or the latest fashion.

'Scalable' content is the sort of content you can write a lot of. The sort of guff that doesn't take a great deal of soul searching.

In relation to NimbleText I easily came up with a basic idea for 'scalable' content generation. Normally, when writing about NimbleText I think about the features, and there's a finite amount I can write. If instead I were to write a short article on every possible specific situation where NimbleText could be used, then you'd be looking at a limitless source of article topics. Think of every type of code it can generate, every example piece of HTML it can produce, every piece of SQL it can concoct, you would be looking at an endless stream of simple, albeit quite repetitive articles. You could churn out such articles at a pretty fast rate. (NimbleText itself could even help with this task.)

Articles such as 'How do I generate insert statements?' may not be the sort of thing that sets the world on fire -- they're never going to attract a viral influx of rabid fans -- but hopefully they'll pander to some fine strange of the long tail of search traffic, and, over time, bring in a trickle of fresh visitors, potential paying customers.

This strategy is a sure winner from an SEO point of view. Wikipedia is essentially nothing but a giant engine built for the creation of Scalable Evergreen content. No wonder it takes first place for just about any search you perform.

So here's the short list of NimbleText-related articles I've written on the bus, since coming up with this strategy:

SQL Master Class (for NimbleText)

It takes less than one bus ride to write such an article, and they're only getting easier. I've got a backlog of thirty such topics and I'm sure with a more concentrated effort I could grow this to many more. Is it worth it? I'm unconvinced, but I'll look at the analytics over time and see what happens.

I've been running this experiment for a few weeks now. Already i've started to see people arrive from new search queries, suited to the articles I've written. The volumes are hardly mega, but the littlest steps bring the most satisfaction.

Read On...


Fri, 22 Feb 2013 22:46:50 GMT

Do *NOT* try this Hacking Script at home

From this answer at stackoverflow, I read:

I saw this one in a bollywood movie. Our hero was busy romancing with his gf until his friend informs him about upcoming college exams. So, he decides to get examination papers by hacking into his college network. This is how he goes about it:

Enters Lab. Opens up a command prompt window. Types - Hack System

And that's it!!...A window pops up- System Hacked

He gets access to all papers and returns to his gf for a romantic song :)

Mind blown. I just had to try it out:

C:\temp>copy con hack.bat
@echo %* hacked!!!!
^Z
        1 file(s) copied.

C:\temp>hack system
system hacked!!!!

C:\temp>hack internet
internet hacked!!!!

C:\temp>hack FBI
FBI hacked!!!!

Drunk with power, yet trembling in terror; I'm sitting here with the door barricaded, certain the feds are going to burst through the door at any moment.

Do *not* try this at home.

Read On...


Thu, 07 Feb 2013 10:19:17 GMT

The 'Should I automate it?' Calculator

Should I automate it?

Here's a clever calculator that let's you answer the age-old question: "is this thing worth automating?"

I put this together a few days ago and I just keep needing to use it! Situations keep coming up where I'm gobsmacked to find that our 'gut-feel' about the relative merits of two approaches is just not borne out by the simplest back-of-the-napkin calculation.

The neat thing about this calculator is that it distills the choice down to its most crucial elements, so you can come up with an answer very quickly.

Once you've plugged in some values and gotten your answer, you can easily share it with those chumps in management or with a clever colleague -- click the 'Save this result' button, and you'll be given a url that you can send around, preserving all the values you plugged in, allowing others to tinker with your calculation and verify everything for themselves. (Implementing that bit was the funnest of the fun. Remind me to show you the 'GetHashyCode' extension method.)

When you take a moment to play with the figures, there's a bunch of things that leap out at you.

First up -- this rather obvious result:

"If you're only going to do it once, it's not worth automating."

That might be quite a shock to some of my automation-happy friends, but I'm afraid the result is unequivocal.

Second: it's amazing how much value you can add by automating something that happens a lot.

Imagine your company has a timesheeting system that takes 10 minutes longer to complete than it should. It's used every week by 20 people, so in the next 2 years it will be filled out approximately 2000 times. You work out a way to save those 10 minutes.... how much effort should you put into making this improvement? Should you bail out if you can't fix it in 1 day? 2 days? 3 days? Here are the figures. It turns out the break even point is 430 hours of work -- around 11 weeks! So yes, if it's going to cost you a whole day of work to improve the timesheeting system -- go ahead and do it! You'd be insane not to!

Jan Ernst Matzeliger (1852 – 1889) Inventor and Businessman

Of course, the benefits of automation are more than just the time it can save. When a task becomes free to do it changes the nature of the value proposition. Read about the amazing impact of Jan Ernest Matzelinger -- a brilliant automator who revolutionised the shoe industry.

The calculator could be simpler, or it could be more complex.

A simpler version would remove the 'hourly rate' fields -- so the answer would be in just hours.

A slightly more complex version would allow there to be a different hourly rate for the person who cleans up when manual work goes wrong. This is realistic. Clean up crews can be expensive. Also the costs of maintaining the automation could be factored in. Cheap automation solutions tend to be very brittle.

Okay -- I'm all out of discussion about this little tool. Use it, share it, automate something today.

 

Read On...


Sat, 19 Jan 2013 12:24:12 GMT

aaron swartz: the early works

I can't stop thinking about, wondering about, caring about, reading about the tragic life of Aaron Swartz. There's a lot I want to write. I think I could fill a book just trying to process what it means, what is an appropriate response, what's it all about. But I'm not going to attempt that.

I've been reading Aaron's blog, on and off, for over ten years. Ten years is a long time. And by my own estimates, those particular 10 years were the longest in history.

Long ago I printed out his HOWTO: Be more productive for multiple re-reads and have returned to it many times since.

I wanted to go back, right back, and try to work out the earliest stuff of his that I read. And I wanted to watch the progression of his ideas as they emerged.

From his blog 'raw thought' -- there's a link to 'Older Posts' which takes you to 'the archive' (grouped by theme).

From there is a link to 'Full Archives' which takes you to the reverse-chronological archives.

These stretch back to May 2005 (the oldest entry on that page is about a server crash after which he had to restart his blogging. Under the so called 'Full archives' section there's no link to anything prior to May 2005.

Now I'm certain he was blogging long before that -- I'm certain I was reading his blog long before that.

Is the stuff before that server crash lost? I hoped not, so I set about locating it.

I clearly remember his powerpoint remix (from 2003!) - it got published in a book of Joel Spolsky's - and I soon tracked that down.

Taking a look at the url suggests a numbered blogging system (from Dave Winer's Radio Userland), and from there it's easy to find all of his prior blog entries.

After a bit of binary searching I found what looks like Aaron's first Hello, world, with article id of '81'.

So I wrote a powershell script to download everything (I hardly think aaronsw would object !!) and found that the articles go from number 81 up to 1691, with a few gaps.

Here's the script.

# Downloads aaron's early stuff
# i've done this the hard way because i didn't have time to do it the easy way.

$client = new-object System.Net.WebClient

$nums = 81..1691

#detected up to 1691  (April 26, 2005)
$nums | % {
    $url = [string]::Format( "http://www.aaronsw.com/weblog/{0:000000}",$_)
    $path = join-path $(get-location) ([string]::Format("aaronsw_{0:000000}.html",$_))
    Write-Host "downloading " $url " to " $path
    $client.DownloadFile( $url, $path )
    
    #sleep for 4 seconds before grabbing, to give the server time to exhale.
    Start-Sleep -s 4
}

Then I wrote a script to walk through those files and create an archive page in the same style as Aaron's other archive pages.

It's not pretty code, it got the job done...

dir .\aaronsw_*.html | % {

    #extract the filenumber out of the name... i should've made this easier.
    $num = $_.Name.Split("_")[1].Split(".")[0] 
    
    #calculate the target url for this file
    $url = [string]::Format("http://www.aaronsw.com/weblog/{0}",$num)
    
    #load the file 
    $article = gc $_.Name

    #grab the title
    $titleRegex = [regex]'h1>(.*)</h1>'
    $title = $titleRegex.Match($article).Groups[1].Value
    
    #grab the time
    $timeRegex = [regex]'<p class="posted">posted ([^(]+) \('
    $time = $timeRegex.Match($article).Groups[1].Value
    
    #output the url, title and time, as html
    $item = [string]::Format('<p><a href="{0}">{1}</a> ({2})</p>',$url,$title,$time)
    $item >> archivePreCrash.html
}

So the result is this fairly complete list of pre-server crash articles:

 

aaronsw archive: early works

 

Now this takes us up to April 2005. And the post-crash articles start in May 2005, so it probably means that everything's accounted for, except maybe a month's worth of blogging. There are some missing articles within that period, and some lost stuff. I can see that he restored it from the wayback machine where possible, but sometimes there was nothing to grab.

There are a lot of gems in there (and of course a bit of drivel: this starts when he was 15). I was going to pull out a few quotes, but I'd rather let you do that for yourself. He was a thoughtful guy. It'd be great if he was still around.

Read On...


Thu, 10 Jan 2013 21:27:11 GMT

Finding (and removing) duplicate files on your hard drive

I generally hold to the philsophy that hard drive space is cheap, and your time is too valuable to waste on optimising hard drive space.

But one of those fun holiday activities, reserved for times when procrastination is at its peak, is to thoroughly clean up a hard drive and make extra room available.

My usual technique is to use SpaceSniffer (found courtesy of Scott Hanselman's tool list) but this time around I suspected that the biggest waste of space was caused by duplicate files (particularly music and photos) taking up a lot of space.

When confronted with a simple problem, the smart guys look for pre-existing solutions. But not me.

I like to employ something I call the 'my way is the best way' philosophy. Other people call it 'not invented here' syndrome, but I prefer to call it 'my way is the best way' because... well, my way is the best way.

thinking about duplicate files

Analysis is more fun than Action

Most of the duplicate-finding tools in this category have a feature where they will automatically delete all but one copy of each duplicate file found. That's not something I'm willing to do, at least not automatically. What I wanted to do was to create the full list of files, and then analyse it, for example in NimbleText. I wanted to create the list of files and then stand back, thoughfully stroking my long beard, just like Pai Mei from Kill Bill.

So I embarked on a special project, codenamed Dinomopabot, a name recommended by my 5 year old daughter who is very clever at these things. The final result is now named 'Dupes.exe': a command line tool for finding duplicate files on your hard drive.


You can browse, clone or fork the source-code, at Bitbucket:

'Dupes' sourcecode



Or download the executable, ready for use:

Download 'dupes.exe'


Here's the built-in help text:

Dupes Find duplicate files, by calculating checksums.

Usage: Dupes.exe [options]
Tip: redirect output to a .csv file, and manipulate with NimbleText.

Options:
  -p, --path=VALUE           the folder to scan
  -s, --subdirs              include subdirectories
  -f, --filter=VALUE         search filter (defaults to *.*)
  -a, --all                  show ALL checksums of files, even non-copies
  -?, -h, --help             show this message and exit

For each file it encounters, Dupes generates a sha256 checksum, with which to compare files. They're short and catchy, they look like this:

271EC103B44960B6A4C6A26FE13682A855133D3D95AC8ED81D7C90FA41571D1F

Cute hey? Almost adoption-worthy.

And for every member of a duplicate file set that the tool encounters, it spits out a row with four columns, separated by bar symbols ('|')

The four columns are:

CheckSum       Sha256 checksum of the file. (Hint: sort by this to get all duplicates together)
DuplicateNum   0 for the first file in the duplicate set, 1 for the second file, etc.
Filesize       In bytes. (Hint: sort by this, if you want to tackle big files first)
Path           Full path and filename for this duplicate.

So you run dupes.exe and direct the output into a textfile (using > [filename]), and from there you can manipulate it (with NimbleText for example), to create a batch file that carefully deletes all the hand-picked, unwanted duplicates of your choice.

Here's an example of a NimbleText pattern you could use with the output of Dupes. This will create a batch file that deletes all but the first copy of each file:

<% if ($1 > 0) { 'del ' + $3 } %>

That pattern is just a piece of embedded javascript (you can embed javascript in NimbleText patterns) that says "if column 1 is greater than Zero, then output the text 'del ' plus the text from column 3." Column 1 is the duplicate number, so it will be greater than zero for all but the first instance of the file. And column 3 is the full path and filename of the duplicate.

Thank you. I hope someone finds this thing useful. Also, please imagine suitably gigantic and terrifying disclaimers attached to this code. I wrote it after all.

Read On...


Mon, 19 Nov 2012 11:05:41 GMT

Harvey, a .net chat server built with RabbitMQ

I've turned into a rabbid RabbitMQ fan in the last week or two, though so far I've only scratched the surface of what this thing does.

Below I'm going to walk through the code for a chat service, built with .net, that uses RabbitMQ for sending and receiving messages. But first a short discussion of Message Queues, RabbitMQ, and how to get this rabbit up and running.

A lengthy discussion is out of scope for this bus ride, but basically:

A message-queue is a piece of middleware for asynchronous communication. (System A sends messages to System B).

MQ's can be optimized for performance, reliability, scalability or any other '*ility' you can think to mention.

There's lots of them, they make different trade offs. Originally they were expensive proprietary technologies (e.g IBM's MQ-Series) - but along with the rise of standards in this area there have arisen various compelling open source offerings.

RabbitMQ is built on Erlang. I don't want to digress into sounding like one of those Erlang-douchebags, but Erlang is a good match for an MQ.

Erlang's initial purpose was to create telecommunications software that was (a) super reliable and (b) hot-swappable. That's a perfect fit for MQ software. It can spin up extra processes without all the heavy lifting of using extra threads, so where a normal OS thread allocates a few megs of memory, Erlang gets away with a few bytes. Extraordinary stuff.

Having said that, the biggest problem with RabbitMQ is that it's built on Erlang. Thus, to install it on your Enterprise-controlled Servers at BigCo you'll need to get Corporate IT's permission to install yet another VM/Platform. Good luck sweet talking those guys. They do *love* to kick up a fuss.

Up and running with RabbitMQ in Under 3 minutes

Everything I'm going to cover in this section is covered in part 1 of Derek Greer's RabbitMQ for windows series. So I'll go extra quick.

To setup a host server for your chatting you'll need to...

  1. Install erlang: http://www.erlang.org/download.html
  2. Set the ERLANG_HOME environment variable to point to the erlang folder under program files. e.g. C:\Program Files\erl5.9.2
  3. Install rabbitMQ: http://www.rabbitmq.com/download.html
  4. Enable the rabbitmq management plugin. from an elevated cmd prompt:
        Go to rabbit's sbin folder, e.g. %programfiles%\RabbitMQ Server\rabbitmq_server-2.8.7\sbin, and run:
        rabbitmq-plugins.bat enable rabbitmq_management
  5. To activate the management plugin, stop, install and start the rabbitmq service:
        rabbitmq-service.bat stop
        rabbitmq-service.bat install
        rabbitmq-service.bat start

  6. Finally, visit http://localhost:55672/mgmt/ and see that your rabbitMQ instance is alive.

It's *that* simple.

Worlds easier than most other installs. Much easier than installing a database, or keeping Adobe Reader up to date.

The only other thing you need do to become a certified .net RabbitMQ developer is use nuget to add a reference to the RabbitMQ.client package.

Introducing Harvey (the simple .net chat client)


Harvey Source Code Here.


Once your rabbitMQ service is up and running, every one on your network can grab Harvey.exe and join in one colossal chat room for all their communication purposes. Every message is delivered to every listener.

The architecture is simple. When you run Harvey.exe it creates two channels, one for sending, one for receiving. The send channel is connected to a fan-out exchange on the server. Each snatchy client also creates its own queue on the server (identified by a guid), which is bound to the afore mentioned fan-out exchange. Thus, when any client sends a message, every client receives it.

Let's step through it.

Set up a channel to the fanout exchange

(Just let it wash over you, this will all make sense by the end)

In form_load we setup everything we need for sending messages. We need a channel to the exchange. The exchange is of type 'fanout' meaning it will send all messages to all queues that are bound to it.

When we 'declare' the exchange, the exchange will be created on the server if it doesn't already exist. Otherwise we will use the existing exchange that has already been declared for us.

In form_load:


            var connectionFactory = new ConnectionFactory
            {
                HostName = "localhost",
                Port = 5672,
                UserName = "guest",
                Password = "guest",
                VirtualHost = "/"
            };

            connection = connectionFactory.CreateConnection();
            channelSend = connection.CreateModel();
            channelSend.ExchangeDeclare(exchangeName, ExchangeType.Fanout, false, true, null);

Sending a message

Assuming we have a textbox (txtMessage) for entering the message we want to post, here's what happens when we click send:


            string input =  txtUserName.Text + " > " + txtMessage.Text;
            byte[] message = Encoding.UTF8.GetBytes(input);
            channelSend.BasicPublish(exchangeName, "", null, message);
            txtMessage.Text = string.Empty; 
            txtMessage.Focus();

That was nice, but we probably want to receives messages back as well -- a chat is not just one way.

Set up a channel to your own queue, for receiving.

We declare a queue, a brand new queue that no one has declared before, and bind it to the fanout exchange.

So messages sent to that exchange will go to this queue, on the server. And we've got a channel to the queue.

(This bit also happens in form_load)


            channelReceive = connection.CreateModel();
            channelReceive.QueueDeclare(clientId, false, false, true, null);
            channelReceive.QueueBind(clientId, exchangeName, "");

Receiving a message...

The very next thing we do in form_load, is start a thread for listening to messages on that channel:


            receivingThread = new Thread(() => channelReceive.StartConsume(clientId, MessageHandler));
            receivingThread.Start();

(Note, forgetting to call .Start() cost me more debugging time than anything else in this whole learning experience)

The following 'StartConsume' extension method was lifted from one of Derek Greer's RabbitMQ articles:

We block the thread waiting for a Dequeue to happen.


        public static void StartConsume(this IModel channel, 
                             string queueName, Action<IModel, DefaultBasicConsumer, BasicDeliverEventArgs> callback)
        {
            QueueingBasicConsumer consumer = new QueueingBasicConsumer(channel);
            channel.BasicConsume(queueName, true, consumer);

            while (true)
            {
                try
                {
                    var eventArgs = (BasicDeliverEventArgs)consumer.Queue.Dequeue();
                    callback(channel, consumer, eventArgs);
                }
                catch (EndOfStreamException)
                {
                    // The consumer was cancelled, the model closed, or the connection went away.
                    break;
                }
            }
        }

And the 'MessageHandler' delegate, above is as follows:


        public void MessageHandler(IModel channel, DefaultBasicConsumer consumer, BasicDeliverEventArgs eventArgs)
        {
            string message = Encoding.UTF8.GetString(eventArgs.Body) + "\r\n";

            txtConversation.InvokeIfRequired(() =>
            {
                txtConversation.Text += message;
                txtConversation.ScrollToEnd();
            });
        }

InvokeIfRequired is just a useful winforms extension method for hopping from a background thread onto the gui thread, taken from this stackoverflow question, and implemented as follows:


        public static void InvokeIfRequired(this Control control, MethodInvoker action)
        {
            if (control.InvokeRequired)
            {
                control.Invoke(action);
            }
            else
            {
                action();
            }
        }

Further reading:

This guy used a similar architecture to what i went with. It's just the simplest architecture imaginable, and he handled 2000 messages a second from a very minimal piece of hardware.

Simon Dixon's article - Getting Started With RabbitMQ in .net

Mike Hadlow has written 'an easy to use .net api for RabbitMQ' called EasyNetQ. One to watch.

As recommended above, Derek Greer has an Excellent Series on RabbitMQ for Windows

Further links to .net development with RabbitMQ

Read On...


Mon, 12 Nov 2012 10:08:14 GMT

LeonBambrick.com

I'm not just a person, I'm a dot com.

When my website was stolen, and I thought I'd never get it back, I started making plans to re-launch somewhere else. Hence, I acquired the domain LeonBambrick.com.

That domain has sat dormant for over a year, until the last week or two, when I decided to put up a list of my online projects, in an easy to digest, html5-friendly, form.

Since you're not doing anything else at the moment, go and have a look:


Visit LeonBambrick.com


It's animated using 'isotope' -- an exquisite jQuery plugin for magical layouts.

Read On...


Thu, 01 Nov 2012 12:33:40 GMT

So your domain has been stolen. What now?

WhoTalking.com
WhoTalking.com. Taken! Then taken back.

I was recently contacted by a local entrepeneur, Michael Q, after his internet domain was taken in circumstances similar to my own.

An intruder gained entry to his email account and used that to get enough information to transfer ownership of his domain away from his registrar.

His registrar was "crazy domains" (in my case it was 'Go Daddy') and the gaining registrar was a french registrar, bookmyname.com (in my case it was WebNames.ru, a russian registrar).

Michael and I wrote back and forth a lot over the next few days. I gave him as much advice as I could, and he kept me informed about his progress. On about the fifth day I got the excellent news that he was back in charge of his domain again.

Michael wrote a complete chronology of the incident: How I Lost My Domain Name and How I Got it Back

And here's my own step by step guide to what happens and what to do if your domain is hijacked, based on my experience and Michael's:

Losing and Regaining Your Domain, Step by Step

  1. Notice a warning in your gmail account that you've logged in using an unknown means from a distant location. Your spidey senses will begin tingling.
  2. Check for deleted emails -- find one from your domain registrar, saying you've transferred away from them. This will include details of the gaining registrar.
  3. Panic and or freak out completely at this point.
  4. Check for email rules that automatically delete any emails from the losing or gaining registrar. take screenshots of and then remove those rules.
  5. Secure your gmail account. change your password, change all your security questions and answers, change your recovery email address, disable any third party apps from accessing it, and disable pop and imap access. Start using 2-step verification.
  6. Think about all of the other things you store in your email account. Other passwords in particular. Start the long process of resetting every password you have. Put it in priority order. Use a proper password management system (e.g. password safe) so that all passwords are unique, complex and as long as possible.
  7. Now, and only now, is it time to stop panicking.
  8. All registrars are ICANN accredited businesses. They must abide by a code of practice, or they will lose their accreditation. One of the rules is that a domain can't hop to a new registrar for another 60 days. So breathe a sigh of relief and realise that you have 60 days to regain control of your domain.
  9. Contact your registrar and inform them that your domain has been hijacked and moved to the gaining registrar. Tell them it is a "disputed transfer", and that you want to fill out their disputed transfer away form. See if they have one (they should).
  10. Contact the gaining registrar -- it's their co-operation that will matter the most. Be nice to them. You may need to register at their site, go ahead and do this.
  11. Tell them your domain was hijacked from the losing registrar and moved to them.

    To establish your identity you may need to send them a scanned copy of your identification (drivers license, passport). It's a scary thing to do, but seems to help, so go ahead and do this if they ask for it.

    (It may also, for reasons that are beyond the scope of this article, help to send them a photo of yourself with a loaf of bread on your head)

    Tell them when you first got the domain, what it was used for. Direct them to the way back machine screenshots of your use. If you don't speak their language you may need to find someone to help translate, or fall back to google translate.
  12. If you receive emails from the thief, take screenshots but do not respond. You have nothing to gain by responding. If however you do respond, I suggest you say some scary cold blooded shit like Liam Neeson's character in Taken. His message was perfectly direct:

    I don't know who you are. I don't know what you want. If you are looking for ransom I can tell you I don't have money. But what I do have are a very particular set of skills. Skills I have acquired over a very long career. Skills that make me a nightmare for people like you. If you let my website go now, that'll be the end of it. I will not look for you, I will not pursue you. But if you don't, I will look for you, I will find you and I will kill you.

    On second thoughts, killing people and even threatening to kill people, are considered a tad illegal in most jurisdictions. So you might want to write that email and then delete it without sending it. A better tactic is to try and draw out the hijacker. Ideally you'll get him to explicitly ask you to give him money to get your website back. People have used emails like this as part of the evidence they provide to the gaining registrar.

  13. Once the gaining registrar has established the facts, you should get your domain back. You may not be able to transfer it to the registrar of your choice until the 60 days have elapsed. You may need to wait while they wait for the hijacker to respond to their questions. Naturally the hijacker isn't going to have a very good story, and may simply fail to reply to their questions. But even this takes time. Patience is necessary. Remember you have 60 days.

That's all I've got. If something like this happens to you, or has happened to you, I wish you the best of luck.

Read On...


Sun, 21 Oct 2012 11:25:23 GMT

kv can remember it for you, wholesale

kv

I've started using a groovy little command-line utility found on the internet, and I have to say I am totally enamored of it.

It was brought to my nebulous attention by my conspirator Rhys, who has it in his 'util' folder of little tools, which I've hg cloned onto my own machine and en-pathed.

The tool in question is 'kv', which is short for 'KeyValue'. You can get it here:


kv.codeplex.com


Imagine you have a lot of ugly things to remember. I know you do.

For example you may need to remember (and frequently type out) the name of your 'dev' server, prod server, staging server, test server and so on.

Get kv to remember it for you!

At a prompt, type:

kv dev MaxServer0412_Tangerine

Now we've stored the rather cumbersome and hard to remember value 'MaxServer0412_Tangerine' against the nice little key name, 'dev'.

So when you type:

kv dev

Two things will happen: the value will get written out into the console. Okay, sure, whatever. But far better than that: the value will get put into your clipboard.

Rhys uses this to store his jargon file. He works in an industry with a lot of domain specific jargon. Every time he hears a new abbreviation that the business people expect him to know, he adds it to his kv stash.

Also - the values don't have to be simple things. They can be gigantic stuff, for example: the complete works of shakespeares. You can pipe a value, or an entire file into the kv command, just give it a key to use.

type 'completeWorks_of_shakespeare.txt' | kv shakes

If you want it to forget one its keys, use the -r switch:

kv -r shakes 

Provenance

The tool itself is based on 'boo' by stevenleeg which is itself based on boom by Zach Holman.

It's clearly better than both of those as it has an even shorter name. None of this three or four letter nonsense. Two letters. That's enough.

Here's the help it provides at the commandline:

>kv -?

kv -- a command-line key-value store integrated with the clipboard.
inspired by: https://github.com/stevenleeg/boo

usage:

kv name fred smith
saves the value, 'fred smith' under the key, 'name'

kv name
retrieve the value 'fred smith' straight to your clipboard.

kv
lists all keys

kv -r name
will remove the key 'name' (and its value) from your store

And two more tips, for super users:

1. You can also pipe a value in, e.g.

echo Hello Fred | kv Greeting
will store 'Hello Fred' under the key 'Greeting'
type File.xml | kv myFile
will store the content of 'File.xml' under the key 'myFile'

Even though, as I say, I found this after it was recommended by a friend, I have to admit that it's my own tool. I wrote it last year in an hour or so, as a simple demo of a little interface I was dabbling with at the time, called stashy. I immediately forgot about it until Rhys rediscovered it.

Utils Folders! Utils Folders! Utils Folders! Utils Folders!

Rhys's 'util' folder is a thing of joy. I think he should make it globally available so people everywhere can clone it, fork it and so on.

I even have a name for it: Rhys's Pieces. Clever hey, Rhys?

Got any little tools in your own utils folder?

Or any way you share your utils folder?



[Image above is of a KV Tank (Kliment Voroshilov), no relation.]

Read On...


Wed, 10 Oct 2012 11:23:32 GMT

Hello IT Department

At one time in my long and extraordinary career (*cough* today *cough*), I had a problem where an offshore IT department stopped replying to my emails. They had closed a support request as complete when it wasn't, and they ignored my every plea to have it reopened. Here's the email I sent, which successfully reopened the thread of communication.

From: Leon
To: IT Support
Subject: IT Service Desk request number SR0154899389 completed

Message:

Please reopen this ticket.

It has been marked as complete but it is not complete.

I have written asking for this to be reopened four times now with no response.

Here is a picture of David Boon.



The pool we are running in the office suggests that I will need to send this email eight times before I do get a response.

Since my money is on just sending it four times, you could help a brother out and respond to me this time. Then I win!

(actual picture may not be David Boon)

You are welcome to reuse it if your plight resembles mine.

Don't worry if you don't know who David Boon is. It kind of helps if you don't. Random inclusion of an unrelated photo seems to be the key factor in inspiring a call to action. I must A/B test this idea against several indifferent IT departments.

(Image of Rob Sitch as an Oz Brother, courtesy of champagne comedy forum).

Read On...


Fri, 21 Sep 2012 11:20:37 GMT

Dialog Between a Man and His Vista Laptop

original article before discard

While continuing the cleanup instigated by the previously mentioned documentary, I threw out quite a lot of stuff.

One piece of paper had the following dialog that I transcribed before discarding. It concerns a man and his Vista laptop.

—Hello laptop.
—Hello user!
—I'd like to change some settings, can I open the control panel?
—[long, long pause] No problem!
—I want to change what happens when I close the lid. What happens currently?
—[extended pause] Well that depends if I'm on a battery or plugged in.
—Why, what's the difference?
—[assume long pauses unless told otherwise] Well, if I'm on battery and you close the lid, I go into sleep mode.
—And? If you're plugged in?
—Well, if I'm plugged in and you close the lid, I go into sleep mode.
—That's the same isn't it?
—Well, I kill a few apps, just to spice it up.
—I see. So what is sleep mode?
—It's a low power mode where applications are paused.
—Suspended?
—No, that's suspend.
—What's suspend?
—It's a bit like hibernate.
—Oh. What exactly is hibernate?
—Well... it's somewhat similar to sleep.
—What's the specific difference between all of those?
—Hmmm. Well, let me see. It's very... There's... Well Okay. I'm not completely sure myself. So I just delete a few extra files to make it convincing. Ah, anyway, you were wanting to change a setting?
—Frankly, I'm a little concerned now. But all I want to do is make sure that if I just close the lid, and if you're plugged in to a power supply, then I want you to just do nothing.
—Nothing?
—Just pretend like nothing's happened. Pretend I haven't event touched the lid.
—Can I kill some apps?
—No.
—Delete a few smallish files?
—No.
—Move the swap file around on disk. Jiggle it a bit?
—Not even that.
—What if I 'clean up' the registry or terminate some services?
—No, not that either.
—Nothing fancy at all?
—Nothing.
—Okay, Sir. It's your dime.
—So when I shut the lid, while you're plugged in to a power supply, what are you going to do?
—Nothing much.
—Nothing much?
—Okay, nothing at all. I'm going to pretend you haven't even touched the lid and that you're still watching very closely. I can do this. I'm a pretty sophisticated operating system you know. I'm not some version two or three operating system. I am Windows Vista, the most eagerly anticipated operating system in the history of windows operating systems. All of this tricky 'do nothing stuff' is considered elementary to a system like me. Go ahead.
—Okay here we go.
—No problem! Bring it on.
—You're definitely ready?
—Ready as ever. A little bit excited actually.
—Here goes.
Man gingerly closes the lid. Without a pause we hear the hard drive grind to a halt. Lights flicker out.
[man performs a facedesk]

Read On...


Fri, 07 Sep 2012 13:50:48 GMT

NimbleText 1.6, Codename Jetboat

Jetboat, the mildly anticipated new release of NimbleText is out now.

If you don't already use NimbleText every single day then you're missing out. NimbleText is a tool for manipulating little bits of data, for formatting text, for performing ad-hoc code generation. It's a versatile little tool that every programmer, DBA, sysadmin, knowledge worker and techie should keep within reach. Here's a two minute guide.


Download NimbleText


Here's a quick rundown of the new features:

Header Variables

You can now refer to the first row of the data from inside any row, using a '$h' pattern.

The new feature works like this. Say you have some simple data that includes a header row:

name, age
Jim, 126
Jenny, 4

Within your pattern you can refer to the first item in the header as $h0, and the second item as $h1, and so on. Like this:

Pattern:
$each+
The person with $h0 $0 has $h1 $1

The result will be:

The person with name Jim has age 126
The person with name Jenny has age 4

This basically means you can stash 'global variables' into the first row and access them in your pattern. Which means you can reuse your patterns more often.

Counting from the right.

Sometimes the data you are parsing is 'jagged' meaning different rows have a different number of columns. This can happen for a variety of reasons. In NimbleText we can't pick and choose the data we are handed. We just do our best to handle for what we get.

When you have jagged data, you often want to read the last column, or the second last column: basically you want to count the columns starting from the left. For example, here's some sporting data:

Name, Scores (ascending)
Stu, 0, 0, 1
Jim, 1, 2, 2, 3, 8  
Stacey, 0, 0, 1, 3, 3, 9, 9

Notice there is a different number of scores for each player. If you only want the last score you can use a negative index to count from the right:

$each+
The best score for $0 is $-0

Returns:

The best score for Stu is 1
The best score for Jim is 8
The best score for Stacey is 9

Download it now, or use the online version.

Release notes are here.

Read On...


Fri, 31 Aug 2012 06:02:53 GMT

On Task Hoarding and Todo Bankruptcy

Last week I watched a British Channel 4 documentary about a chronic hoarder named Richard Wallace. Fascinating stuff.

This was a man who hadn't had a bath in years because his bath, like everything else in his house, was covered to the ceiling in piles of collected junk. To get from one room to the next he would have to swim over the top of his junk pile, ducking under the top of the doorway. And yet he was a fairly normal guy. He wasn't like some angry Smaug, fighting to protect his golden hoard. He had a well developed sense of humour, and you could carry out a normal conversation with the guy.

Yet he had a profound lack of insight. Despite his incredible existence (he slept in a chair, his bed was covered in ceiling-high junk), he didn't see see that he had a psychological syndrome. Pay attention to this, because it's kind of the point: He didn't believe he had an excessive hoarding habit, he felt his real problem was a shortage of storage.

I think what scared me was that he was a little like me. Or a little like you. So it got me thinking about my own hoarding tendencies.

It's normal to do some amount of collecting. I've always done a little here and there. I have boxes and boxes of books under the house. I have a record collection somewhere. I have a jar of buttons (more on that later). But all of that is under control. (After watching the documentary I immediately threw away a box of msdn magazines that I've been holding onto for too long.)

Instead, there is a completely different form of hoarding I engage in, that has gotten out of control.

The thing I collect is incomplete projects. Unfinished work.

My list of incomplete projects is my own personal crazy hoard.

To get from one task to the next, I need to swim over the ceiling-high pile of incomplete tasks, stacked up from every stray project idea I've ever had.

Like a crazy hoarder I mistake the root cause of my growing mountain of incomplete work. The hoarder thinks he has a storage problem (when he really has a 'throwing things away problem'). I say I am 'time poor' as if the problem is that poor me is given only 24 hours in a day. It's more accurate to say... what exactly? It seems crazy for a crazy person to use his own crazy reasoning to diagnose his own crazy condition. Maybe I too easily add new projects to my list, or I am too reluctant to exit from unsuccessful projects. Perhaps I am too reluctant to let a task go, to ship what I've done. They're never perfect, never good enough.

And I know I'm not alone in making the easy claim that I am 'time poor'. So many people claim to be time poor, when really we are poor at prioritizing, or poor at decisiveness, or don't know how to say 'no' (...to other people, to our own ideas).

If only I had a hidden store of time, or if only I had magical organisation tools, or if only I could improve my productive throughput, then, only then would I be able to get things done, to consolidate the growing backlogs and todo lists into one clear line of work, and plough through it like an arctic ice breaker carving its way through a sheet of ice.

So I have to declare todo bankruptcy. Throw everything out and start again.

I've gone back to the trello boards and slashed and pruned and archived and revised and reordered until the whole todo landscape started to make sense. I've dragged in items from other sources (from moleskine's and from starred items in gmail, from 'TODO' comments in my code, from various TODO.txt files buried on my hard-drive... from all over.)

First up, a lot of projects have moved from the maybe pile to the 'never no way' pile.

Example of projects that are officially cancelled as of this moment are:

Not To Do

  1. 'Cop Dog Buddies' -- movie script about two mismatched police dogs thrown together to hunt down their masters' killers.
  2. 'Registry on Rails' -- the web development framework from hell.
  3. Orable -- (pronounced "'orrible") my poor man's oracle IDE
  4. OCD-targeted one-page website "have i left the iron on?"
  5. A life-sized full-body tattoo of my own body, all over my body.
  6. My pro wrestling career
  7. My rap battle ambitions
  8. A range of Pinal Dave T-Shirts
  9. Twee -- a micro-blogging service where posts can only be three words long and must be valid dictionary words in your language.
  10. 'Vampurr' trilogy -- epic love-triangle between goth-girl tattooist, ear-stretching vampire and shape-shifting battle-cat.
  11. Word as a database -- it's Word. As a database.
  12. Operation Butter-knife
  13. Choosing the right fonts
  14. Operation 'Taser my enemies in the face'
  15. Boss monsters feature in unreleased malware easter egg
  16. 'Silmarillion with sock puppets' -- treatment for a feature film
  17. 'Top Gut' -- movie script about the fat camp for the fattest of the fat

Okay, that's a slightly modified version of the real list. The real list is a lot longer and a lot sadder. But the actual thing I'll actually do next is:

To Do

1. Put out NimbleText 1.6.

People have been nagging me about this for a while, and it's pretty much ready, if I can just stop distracting myself with all the other craziness.

Stay tuned.

Read On...


Mon, 16 Jul 2012 11:53:25 GMT

Developer UI Done Right: Mercurial Commandline!

Developer tools are famous for having bad usability. In Code Complete Steve McConnell listed this as a case of 'the cobbler's children go barefoot'. (A fancier term for the same effect is 'vocational irony.' you know, like House MD).

But here's a case where User Experience in a very very developer-specific tool is surprisingly polished, in a way that you wouldn't quite expect.

Follow along if you will...

I'm using mercurial and I decide my work is ready to be pushed. At this point, the stack of tasks in my head (the things I'm trying to achieve) just says "push."

I try to push.

C:...>hg push
pushing to ...
searching for changes
abort: push creates new remote head a751ec334b3e!
(you should pull and merge or use push -f to force)

Interesting! It failed, but not in the typical 'pages and pages of angry red error messages' way. Instead I get a one line error description and then this delicious hint -- I can use 'pull and merge' to get past the problem.

(Note that I've elided any personal details, and hashes have been modified to protect the innocent)

So now the stack in my head says "pull, merge, push".

So I pull.

C:...>hg pull
pulling from ...
searching for changes
adding changesets
adding manifests
adding file changes
added 2 changesets with 1 changes to 1 files (+1 heads)
(run 'hg heads' to see heads, 'hg merge' to merge)

This succeeded nicely. But again there is a hint. Having performed the pull, it looks like I need to merge.

The hint reinforces what the previous command told me and helps me to confidently move in the direction I was already headed. (Or: it serves to remind me that I need to merge, in case I had forgotten). The stack in my head now says "merge, push."

I attempt the merge.

C:...>hg merge
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)

It tells me the merge succeeded. This is pretty spectacular all by itself, but for users of distributed version control systems it's a common enough occurrence, so I'll skip over that bit. Again, I get a neat little hint. It reminds me to commit before I do anything else. So the stack in my head now says "commit, push"

I attempt to commit...

C:...>hg commit
...

This last command gives me only happy messages, which I've not included as they're of no interest. There is no hint what to do this time, as mercurial does not remember that my ultimate goal here was to push. But I haven't forgotten that simple goal. So I try the last remaining step: I push.

C:...>hg push
pushing to ...
searching for changes
adding changesets
adding manifests
adding file changes
added 2 changesets with 1 changes to 1 files

And everything is right in the world.

There's something just so neat about the hand-holding that mercurial performs throughout the exercise. I want to pick it up and cuddle it and rub my nose against its little nose.

(of course frequent mercurial users will know shorter and slightly better ways to achieve this same thing, but these little step by step hints are completely adequate for the occasional user like me.)

Now why was all of this amazing? As I said, it's a developer tool, so that's already a good reason to expect poor UI.

But secondly, it's an open source tool. There is a belief that open source software favours usability less than other things.

Third, the hints that were so helpful are a form of documentation. And open source projects very often get criticised for their lack of documentation. Again we have a nice counter example.

Fourth -- it's a commandline tool! A commandline tool! This is a category of software that is not known for being helpful and forgiving to the beginner or infrequent user. Yet mercurial is demonstrating a way in which it is possible to be kind to such users.

All up: I continue to find it nice on a whole bunch of levels. Hat tip to mercurial.

(Next article in this series: "Mercurial And How To Undo a 'hg -forget *' Command, Or, Mercurial, You Evil Unusable Bastard, Why Hast Thou Forsaken Me? Undo! Undo!")

Read On...


Fri, 25 May 2012 13:36:19 GMT

Rediscovering the Amstrad CPC 6128

I recently inherited the original instruction manual from the first computer my family ever owned, the Amstrad CPC 6128 User Instructions.

Flicking through this magnificent compendium has sent me on a serious nostalgia trip. It wasn't long before I downloaded an Amstrad emulator (or two) and began to relive some of the programming fun of Amstrad Basic.

The book takes you through every aspect of the computer, the hardware, the operating system, and two programming languages (BASIC and Logo). And it starts from absolute beginner level, in a way that no modern set of instructions ever needs to. Here's an excellent example:

Important
When you reach the right hand edge of the screen by entering 40 characters on a line, the next character will automatically appear on the following line at the left edge of the screen. This means that you should NOT press [RETURN] as those of you accustomed to typewriters might press a carriage return towards the right edge of a page.

The computer does this automatically for you, and will react to an unwanted [RETURN] by printing an error message - usually a Syntax error, either there and then, or when the program is run.

...that's not a detail typically cover in a more recent text. And it recurs throughout the early chapters of the book, as they explicitly tell you where to hit return in case you've miraculously forgotten. They only stop adding the word [RETURN] when they get up to teaching you about the return keyword (used after a gosub, for awesome fun times.)

Demonstrating the use of GOTO, GOSUB and RETURN leads to this interesting reflection:

See how much tedious typing we've saved ourselves? Well designed subroutines are a principal part of computing. They lead to 'structured' programs, and develop good programming habits.

...all by itself this seems to conflict with the ideas put forth in 'Go-to Statement Considered Harmful' but the very next paragraph really takes it up a notch:

Always bear in mind when writing sub-routines, that you do not necessarily have to Jump into' the sub-routine at the same point, i.e. its beginning. A sub-routine written from lines 500 to 800 can be called by: GOSUB 500, or GOSUB 640, or GOSUB 790.

...this isn't what you call the gold standard of structured programming. ;-)

The more I got into it, the more I enjoyed it. I was surprised at how much I'd forgotten, but equally surprised at how ready those memories were to spring back into place. My friend Dr Richard (of brisbane parks fame) pointed out that by reawakening such old neurons and marking them as new again, the brain is bound to believe that those memories are of very high importance and mark them as always hot. So now it's likely I'll never forget Amstrad Basic again.

One intriguing idea from the Amstrad, which seems to have been abandoned by the side of the information highway, is 'the copy cursor'.

Consider this startling example of using 'the copy cursor' to correct a typo. Their example builds on this code sample, which has a missing 'r' on line 10:

10 input "what is you name";a$ [RETURN] 
20 input "what is your age";b [RETURN]
30 print "I must say";a$;" you dont 
look";b;"years old" [RETURN] 

Here's how a coding ninja would fix that typo, in the copy cursor era:

Copy Cursor Method
The copy cursor is another cursor (in addition to the one already on the screen) which comes into view when you hold down [SHIFT] and press one of the cursor keys. It then detaches itself from the main cursor and can then be moved around the screen independently.

To correct the mistakes in line 10 and 30, hold down the [SHIFT] key then press the cursor up key until the copy cursor is positioned over the very beginning of line 10. You will notice the main cursor has not moved, so there are now two cursors on the screen. Now press the [COPY] key until the copy cursor is positioned over the space between 'you' and 'name'. You will notice that line 10 is being re-written on the last line and the main cursor stops at the same place as the copy cursor. Now type in the letter 'r'. This will appear on the bottom line only.

The main cursor has moved but the copy cursor stayed where it was. Now press the [COPY] key until the whole of line 10 is copied. Press [RETURN] and this new line 10 will be stored in the memory. The copy cursor disappears and the main cursor positions itself under the new line 1 0. To correct the second mistake, hold down [SHIFT] and press the cursor up key until the copy cursor appears over the very beginning of line 30.

Press [COPY] until the copy cursor is positioned over the quotation marks next to say. Now press the space bar once. A space wiil be inserted on the bottom line. Hold down the [COPY] key until the whole of line 30 is copied, then press [RETURN].

(Using an Amstrad emulator with a windows keyboard, I found that the Pg-Dn key acted as the [COPY] key).

But software quality assurance and refactoring magic aren't just left up to the wonderous copy cursor. There's another awesome tip on detecting errors in your code. The trick is to write your code in lowercase and see that the interpreter finds your keywords and shifts them to uppercase:

IMPORTANT
In the above program, and in later chapters and listings in this manual, BASIC keywords will appear in upper case (CAPITAL) letters. This is how keywords appear when a program is LISTed by the computer. In general it is preferable that you type instructions or programs using lower case (small) letters, since it will help you spot typing mistakes when LISTing the program - (because the mis-typed BASIC keyword will NOT be converted to upper case).

I find something adorable in their vociferous way of describing the technique. The modern age is all too brief in its belting-around-the-headedness-about-the-simple-things. These days it's all "merge this, rebase that, man page if you don't grok" and the eyes are left spinny.

I've had some recent fun building simple programs on the Amstrad (emulators) but there's too much to cover here. I'd like to write a little about it, if I find the time, but that's enough for now.

Just reviewing the book was a joy in itself. Whoever said "nostalgia isn't what it used to be" must've been one of those filthy Commodore 64 programmers, I guess.

Read On...


Sat, 12 May 2012 02:59:08 GMT

Just Wally

The apocalypse came suddenly. Some kind of worm, virus, trojan -- some kind of Mark Russinovich doomsday scenario. It spread so fast no one had a chance to react. It lit up every computer screen, obliterating every computer user in the world. Every last worker was obliterated, right at their desk. All that remained was a tiny pile of ashes on every seat.

Only Wally was spared. While everyone else was at the desks working, Wally was wandering the halls, holding a coffee cup.

'Just Wally' is a cartoon that removes all the unneccessary elements from Dilbert, and leaves just the hero himself, Wally, wandering the empty building, holding meetings with himself, filling his loneliness with imagined interactions.

Wally has always been the truest character in Dilbert. I've met a few Dilberts in my time. I've met a few Pointed Haired Bosses. But just about everyone is at least part-Wally. And more than a few have been pure-Wally. You know who you are.

Some people theorise that the true story of 'Just Wally' is that Wally is the one who died. This is his limbo, wandering alone, unable to interact with the living.

Others say Wally has fallen into a coma. This is his extended delusion. He cannot tell dream from reality, sarcasm from seriousness. What exactly is a dream? What exactly is a joke?

The words of JD Salinger are relevant here, as always.

"It isn't just Wally. It could be a girl, for goodness' sake. I mean if he were a girl - somebody in my dorm, for example, - he'd have been painting scenery in some stock company all summer. Or bicycled through wales. Or taken an apartment in New York and worked for a magazine or an advertising company. It's everybody, I mean. Everything everybody does is so - I don't know, not wrong, or even mean, or even stupid, necessarily. But just so tiny and meaningless and - sad-making.

And the worst part is, if you go bohemian or something crazy like that, you're conforming just as much as everybody else, only in a different way."

Tiny and meaningless and sad-making.

Tiny and meaningless and sad-making. 'Just Wally' makes us stop and ponder the futility of everything we do, everything we think and everything we are.

In the style of Garfield minus Garfield, Just Wally plays upon the maxim of my old buddy Antoine de Saint-Exupery:

"Perfection is achieved not when there is nothing more to add, but when there is nothing left to take away"

Read On...


Tue, 08 May 2012 04:22:21 GMT

The Correct Order for a First Time Viewing of The Lord Of The Rings

After reading Scott Hanselman's post about introducing your younglings to Star Wars, I was intrigued by the suggested 'Machete order' (courtey of Rod Hilton)

  • 4 - Star Wars: A New Hope
  • 5 - Empire Strikes Back
  • 2 - Attack of The Clones
  • 3 - Revenge of the Sith
  • 6 - Return of the Jedi

Which lead to deep conversations with myself about which order I should use when introducing my daughers to 'The Lord of the Rings'.

The three films can be arranged into 6 possible non-repeating combinations:

  • Fellowship, Towers, King
  • Fellowship, King, Towers
  • Towers, Fellowship, King
  • Towers, King, Fellowship
  • King, Fellowship, Towers
  • King, Towers, Fellowship

All of which have their own pluses and minuses, but none of which would qualify as a true 'machete' reordering.

I finally settled on the following order, which you'll agree is the best possible version of events:

  • 1. The Two Towers -- A good story always starts in the midst of the action, and leaps past the boring parts.
  • 2. The Hobbit, An Unexpected Journey -- having established the story we now move learn the origin of the Ring and Gollum.
  • 3. How to Train your Dragon -- the loveable Toothless and Hiccup show us that not all dragons are nasty Smaugs.
  • 3a. Read all of the books -- that way you can complain bitterly about the missing 'Scourge of the Shire' segment during:
  • 4. Return of the King, Disc 2 -- 5 minutes of chucking a ring in a pit, a quick eagle ride, and two hours saying goodbye.
  • 5. Return of the King, Disc 1 -- Awesome battle scene. Best war ever.

I dub this the Chop-Suey Reordering, and in line with Oracle's copyright on the arrangement of the Java Api's, I claim ownership of this and all derivative reorderings of the LOTR franchise.

Read On...


Fri, 23 Mar 2012 12:37:13 GMT

A new era for Android.

Occasionally, marketers send me press releases in the hope I'll blog about them. Ordinarily I refuse to be manipulated by such a ploy, but I thought this one about android was worth a little discussion. I've always thought that android phones look interesting but only from the point of view of a tinkerer. This new direction seems to offer something more.

Here's a few relevant excerpts:

food phone

Android, the world's leading free, open source platform for everything beyond smart phones, and the world's most popular phone amongst Android software developers and Google employees, is proud to announce the discovery of their first Consumer.

The Android developer community first suspected the existence of the Consumer after finding non-Google IP addresses in the log file of an Android Developer Forum. The discovery was quickly escalated to Google management who sent a rapid response Privacy Intrusion Team to perform expanded analysis of his web searches, browser, email and telephone usage. They were thrilled to discover that the lurker was a genuine Android customer who was neither an Android software developer or a Google employee.

The potential existence of such a Consumer had been hotly debated on Android developer forums for years. But even the most optimistic Android enthusiasts had assumed that the debate was purely theoretical.

Google had previously spent millions of dollars placing 'Angry Birds' in their 'Google Play' app store, in the hope that it could potentially attract a Consumer to consider using the Android platform for Consumer Purposes. Google's Privacy Intrusion Team have revealed that analysis of the Consumer's correspondence offer no clear rationale for why he purchased an Android phone from a market place crowded with more suitable offerings. Skeptics have taken this as an indication that the Consumer's existence could be the result of Google Finland's controversial 'tag and release' program where members of the public were anaesthetised, given an Android phone, and released back into the population.

This new phase of the Android platform is an exciting time. Predicting an influx of Consumers, developers have quickly raced to make the phone more technically intimidating and to provide an even more fractured range of devices. Google employees remain unaware of anything that has happened to non-Google employees.

The Consumer is now considering getting into Android development, and has recently taken a job at Google.

Crazy times. Next they'll be announcing the discovery of a teenager who wants a Zune.

Read On...


Sat, 07 Jan 2012 10:57:31 GMT

Mind-boggling Demo of New Gaming Genre, aka Folder-Based Hangman, aka Fun with Recursion

I had a crazy idea recently for a new game - a game that defines an entire new *genre* of computer game, and a new style of programming computer games. Whether or not this idea will go on to change the way all computer games are written, I will let history decide.

It's such a simple idea that I don't know how it couldn't have possibly existed earlier. It doesn't require massive graphic capabilities, no CUDA NUMA GPGPGPU and the like -- it's an idea so profoundly simple that you'll be scraping your jaw off the floor with a spoon before you finish reading this blog post.

You run the 'game' and it sets up a directory structure to represent every possible state of the game. To play the game, you inspect the current folder, look at the currently available sub folders, and choose which one to navigate into. Each sub folder you see represents the next possible state of the game.

There is no executable program running when you are playing. The game is just your act of navigating the folder structure. It's a clever form of madness!

Here's some screenshots that show me playing the game, in a command prompt.

I've changed my prompt to just a 'greater than' sign, by typing 'prompt $g', to make it cleaner. Old-school DOS wizards do this kind of thing all the time. Hipster kids, try and keep up.

First I type 'dir /b' to get a clean view of the current folder.

There is only one folder, '__PLAY HANGMAN__' so I navigate into it by typing  'cd[TAB][Enter]'. The game has begun.


Looking in that folder I see the empty scaffold, three underscores (representing a 3 letter word) and the available letters listed down the left hand side. We're playing with a reduced alphabet to keep the number of permutations within a reasonable amount.


My first guess is the letter 'A'. To make this guess I type 'cd A[tab]'. When I type 'dir /b' to inspect the new state of the game I see that it was a good guess, as one of the letters of the word has been filled in. Also there is an 'x' next to the 'A' indicating that that letter has been guessed. That's all there is to it. Hear that pop? That was your cerebellum exploding through your temporal lobe.


If I try guessing 'A' again, all I find is a folder containing a file named 'You have already guessed that letter.' To undo my mistake I back out by typing 'cd ..' (You could, theoretically use this technique to undo any move, but that would be unsportsmanlike.)


A couple of moves later and I've guessed every letter:


The word is 'CAB'. There's no particular fanfare. Just the word 'WIN' declaring my victory.

Okay, now you've seen the whole thing I hope you're aching to not just download the game, but to write your own entry into this brave new genre. You could do for Gehtto-Folder-Games what John Carmack did for first person shooters!

I'd love to see an implementation of tic-tac-toe, aka, naughts and crosses. Also, hangman could be minified by using junctions (i.e. symbolic links) -- I'd love to see that implemented. The possibilities for new games are pretty much endless. Maybe six or seven.

Okay let me level with you. The mathematics of this idea were just ridiculous. For a full 26 character alphabet, I would've killed my little computer. (Care to accurately calculate how many folders are created for the given alphabet?) It's all based around N-factorial where N is the size of the alphabet. Factorial is not something you want to see in the real world.

I'm on holiday at the moment, so the only computer available to write it on was my dell mini, which doesn't have any serious coding environment. So rather than write it as a console app in visual studio (or even a powershell app) I wrote a javascript page that generates a batch file. It's very niche.

This also turned into an opportunity to learn the ins and outs of getting recursion wrong with javascript. The most common mistake you make with recursion in javascript, it turns out, is forgetting to declare a local variable. This means that the variable becomes global and your recursion goes nuts. Don't make that mistake. When your code is creating subfolders all over your hard drive it's a particularly painful mistake. It took me considerably less time to write the program than it did to debug it, and (considerably*considerably) less time to debug than the time to clean up all the folders left in unexpected places.

But the funnest bit was the ascii sprite code.

I had one array that showed the final hanged man:

var hangyPicture = [
'   _______   ',
'   I     I   ',
'   I     O   ',
'   I   --I-- ',
'   I    I I  ',
'   I         ',
'--===--      '];

(Side point... why wasn't my ascii art better than this? Because | and \ are not valid in folder names.)

And I had another array that showed how many misses were required before a given character of the hangyPicture was shown:

var hangyMask = [
'             ',
'             ',
'         1   ',
'       33233 ',
'        4 4  ',
'             ',
'             '];

Then, with those two arrays in place, I can work out the names of the folders to create. I walk through the mask, one character at a time, and compare the digit I find to the current number of missed guesses. If the digit I find is less than (or equal to) the current number of missed guesses, then I include that character in the folder name, otherwise I mask it out with a space. Ah, I give in -- it's easier to just show the code:

for (var h in hangyPicture) {
  // use hangyMask[h] and numberOfMisses to mask chars out of hangyPictures[h] 
  for(var i = 0; i < hangyMask[h].length; i++) {
    if (hangyMask[h][i] == ' ' || hangyMask[h][i] <= numberOfMisses) {
      folders[h] += hangyPicture[h][i];
    } else {
      folders[h] += ' ';
    }
  }
}

Okay. Now you've been enlightened with the future of ultra-ghetto folder-based gaming, go ahead and make your own. I can wait.


Here's the code


The accompanying program is a piece of javascript that creates a windows batch file. You run the batch file.

Read On...


Sun, 27 Nov 2011 03:07:28 GMT

Got CSV in your javascript? Use agnes.

The only things that will survive the forthcoming nuclear+zombie apocalypse are cockroaches, javascript and CSV.

So I've written an open source javascript library, agnes.js, that the cockroaches can use for dealing with CSV from javascript. And in the brief pre-apocalypse era you can use it too.


Download the zip


I've written before about how CSV starts off looking easy, but quickly descends into a world of insanity. So in javascript land, let agnes handle all the nasty quirks and edge cases (embedded delimiters, qualifiers, nulls and so on).

I wrote a bunch of unit tests to go with it, so you can tell exactly what it does with each weird bit of input you can throw at it.

You can download it from agnes.codeplex.com

This was a particularly fun little bus project, and what I like best about agnes is the content you get when you download her.

The readme file has executable examples, that work by having a chunk of code displayed in a div, which is the exact code that is grabbed and executed when you click 'Try it'.


Browse source code


I like the unit tests that come with it, and the little unit test runner. I could've gone really overboard with it, but I stopped myself before it went too far.

And I like the sample that performs Csv to Json conversion, back and forth, back and forth. My favourite part of that is using html entities in the button titles, for left and right arrows.


Try it out


Now that I've got agnes out of the way, hopefully I can focus on my new bilion dollar idea, youmustget.com

Read On...


Sat, 12 Nov 2011 00:39:08 GMT

I went to write down a book name and founded an internet empire instead.

tron motorcycle just 55K AT AT dog costume you must have

Yesterday Joel told me, 'hey you really should read "The Big Short" by Michael Lewis' -- and I thought, yes, I'll write that in my list of books I must get and when I have a chance I'll order it and all the other books in my list of books i must get.

Looking through my iphone I was shocked to find I don't even *have* a list of books I must get. I've got a list of which Woody Allen movies I haven't seen, and I have a list of which Jeeves and Wooster books I own (or own twice) so I don't accidentally buy them again (or again again), but no "Books I must get".

And I realised it's not just books that I keep forgetting. It's everything in our stupid materialist world. It's gadgets, music, movies, games, t-shirts, toys, gifts for my wife, baby stuff, apps, power tools -- a whole big fat materialist world full of stuff I must get, that, realistically i'll never get, but which my inner taxonomist wouldn't mind having a list of somewhere.

Suddenly, before I could stop them, my hands had rushed off and spent 9.95 to buy all of the following websites...

  • http://things.youmustget.com
  • http://books.youmustget.com
  • http://movies.youmustget.com
  • http://games.youmustget.com
  • http://gadgets.youmustget.com
  • http://apps.youmustget.com
  • http://stocks.youmustget.com
  • http://software.youmustget.com
  • http://dvds.youmustget.com
  • http://jokes.youmustget.com
  • http://vaccinations.youmustget.com
  • http://tattoos.youmustget.com
  • http://cars.youmustget.com
  • http://piercings.youmustget.com
  • http://hookers.youmustget.com
  • http://starwarsstuff.youmustget.com
  • http://drugs.youmustget.com
  • http://websites.youmustget.com
  • http://cakes.youmustget.com
  • http://clothes.youmustget.com
  • http://bikes.youmustget.com
  • http://girlfriends.youmustget.com
  • http://babystuff.youmustget.com
  • http://diseases.youmustget.com
  • http://travel.youmustget.com
  • http://tshirts.youmustget.com
  • http://shirts.youmustget.com
  • http://wines.youmustget.com
  • http://beers.youmustget.com

...and so on, because i bought 'youmustget.com'.

And now I have a slight dilemma. I already own too many urls that I'm not using (this brings my total internet empire to 11.5 sites) And I don't have time to execute on even the simplest ideas in my idea log.

So: how can I crank out a social recommendation/shopping app in under 5 bus trips!?

I want something that produces an output a little bit like this is why i'm broke dot com but where the recommendations come from people i respect, and with affiliate dollars flowing into my wallet on every recommended purchase. (And i'd like to come up with a less-sleazy way to monetize, if possible, but I do have to recoup that $9.95 somehow)

I've begun by creating a Trello board to capture all my ideas. I've got details for the home page, a products page, a user page, and a topic page. I've got a backlog of features that I won't implement at first, and I've got a list of ideas for what technology I'll use where. Next I'll put together some screen mockups and put them in front of my extended team of insult generators lunch buddies.

In the mean time I'll need to keep a cricket bat handy with which to repel the hordes of nodding VCs.

Thoughts?

Read On...


Hey good looking!

click here to visit the secretGeek archives!

Go on... continue through to the archives


^Top

newest

NimbleText 2.0: More Than Twice The Price! NimbleText 2.0: More Than Twice The Price!
A Computer Simulation of Creative Work, or 'How To Get Nothing Done' A Computer Simulation of Creative Work, or 'How To Get Nothing Done'
NimbleText 1.9 -- BoomTown! NimbleText 1.9 -- BoomTown!
Line Endings. Line Endings.
**This** is how you pivot **This** is how you pivot
Art of the command-line helper Art of the command-line helper
Go and read a book. Go and read a book.
Slurp up mega-traffic by writing scalable, timeless search-bait Slurp up mega-traffic by writing scalable, timeless search-bait
Do *NOT* try this Hacking Script at home Do *NOT* try this Hacking Script at home
The 'Should I automate it?' Calculator The 'Should I automate it?' Calculator
aaron swartz: the early works aaron swartz: the early works
Finding (and removing) duplicate files on your hard drive Finding (and removing) duplicate files on your hard drive
Harvey, a .net chat server built with RabbitMQ Harvey, a .net chat server built with RabbitMQ
LeonBambrick.com LeonBambrick.com
So your domain has been stolen. What now? So your domain has been stolen. What now?
kv can remember it for you, wholesale kv can remember it for you, wholesale
Hello IT Department Hello IT Department
Dialog Between a Man and His Vista Laptop Dialog Between a Man and His Vista Laptop
NimbleText 1.6, Codename Jetboat NimbleText 1.6, Codename Jetboat
On Task Hoarding and Todo Bankruptcy On Task Hoarding and Todo Bankruptcy
Developer UI Done Right: Mercurial Commandline! Developer UI Done Right: Mercurial Commandline!
Rediscovering the Amstrad CPC 6128 Rediscovering the Amstrad CPC 6128
Just Wally Just Wally
The Correct Order for a First Time Viewing of The Lord Of The Rings The Correct Order for a First Time Viewing of The Lord Of The Rings
A new era for Android. A new era for Android.
Mind-boggling Demo of New Gaming Genre, aka Folder-Based Hangman, aka Fun with Recursion Mind-boggling Demo of New Gaming Genre, aka Folder-Based Hangman, aka Fun with Recursion
Got CSV in your javascript? Use agnes. Got CSV in your javascript? Use agnes.

Archives Complete secretGeek Archives

TimeSnapper -- Automated Screenshot Journal TimeSnapper: automatic screenshot journal

25 steps for building a Micro-ISV 25 steps for building a Micro-ISV
3 minute guides -- babysteps in new technologies: powershell, JSON, watir, F# 3 Minute Guide Series
Universal Troubleshooting checklist Universal Troubleshooting Checklist
Top 10 SecretGeek articles Top 10 SecretGeek articles
ShinyPower (help with Powershell) ShinyPower
Now at CodePlex

Realtime CSS Editor, in a browser RealTime Online CSS Editor
Gradient Maker -- a tool for making background images that blend from one colour to another. Forget photoshop, this is the bomb. Gradient Maker


[powered by Google] 


How to be depressed How to be depressed
You are not inadequate.



Recommended Reading


the little schemer


The Best Software Writing I
The Business Of Software (Eric Sink)

Recommended blogs

Jeff Atwood
Joseph Cooney
Phil Haack
Scott Hanselman
Julia Lerman
Rhys Parry
Joel Pobar
OJ Reeves
Eric Sink

Aggregated Links

proggit
dzone
hacker news
dot net kicks

Human Link Machines

interesting finds
a continuous learner's weblog
arjan's world
weekly link post

LinkedIn profile
LogEnvy - event logs made sexy
Computer, Unlocked. A rapid computer customization resource
Aussie Bushwalking
BrisParks :: best parks for kids in brisbane
PhysioTec, Brisbane Specialist Physiotherapy & Pilates
home .: about .: secretGeek RSS .: © Leon Bambrick 2012 .: privacy

home .: about .: RSS .: © Leon Bambrick 2012 .: privacy