I've been working on a personal project called HireDuck for a few months now. It's a web application that manages your job applicants. By allowing you to create custom job application forms, applicants can fill out the answers to any questions you want to ask. You get notified whenever someone applies and you can view their answers and resume online.

It's a totally free tool that is aimed at smaller businesses who are hiring and want something a little better than email and spreadsheets. I'm still actively developing it, so if you're interested I'd love it if you sign up and give it a try. And as always, I welcome any feedback or suggestions.

Here is a quick overview of how it works. First you add a posting, give it a name and some other details. Nothing too fancy.

Next choose the questions you want to ask in your application. The questions are arranged into groups, so you may have a "Requirements" group, followed by a "Nice to have" group:

Next you'll be given an info page for your posting. Your posting will be private until it is published.

You are given a link which will be what you provide to any potential applicants. If you visit that URL you can try out your own application. It will look something like this:

When anyone submits an application, you will receive an email with a link to view and review the application.

You can manage your applicants for an application with a simple thumbs up/thumbs down system. You can also give applicants you really like a gold star.

That's really all there is to it. It's a simple tool designed to ease the interview process. Nothing super process heavy, just something that is better than email and a spreadsheet. It's flexible and powerful, yet simple and elegant. And it looks great on a phone too!

 Once again, it is 100% free. No ads, and I'm really excited about this. Even if you're not a company owner or a hiring manager, I would still encourage you to give it a try and see what you think.

Cheers, Rich
By Richard Rout
Only used for Gravatar avatar.

My Nexus 5 recently got updated to Android 5.0 Lollipop. It's a nice update, I really like the design.

I was browsing some websites and one website had a custom colour in the chrome nav bar. I thought that was so cool, so I had to find out how to do it. It's super easy, you just put a meta tag in the <head> of your site:

 <meta name="theme-color" content="#1b1b1b" />

It takes your website from this:


To a snazzy looking this:

It also affects the app switcher view. Here is a before and after:


Cheers, Rich
By Richard Rout
Only used for Gravatar avatar.

When I have a problem and I spend a few hours scouring the internet only to find nothing related, I'm forced to draw one of three conclusions:

  1. I'm searching for the wrong thing.
  2. No one else has had this problem before. Ever.
  3. It isn't a real problem and I've done something dumb to get myself into a pickle.

I'm not sure which one this problem fits into, but I hope it will help someone anyways.

We recently implemented friendly error pages into our ASP.NET MVC app, which was a pain in of itself. Ben Foster outlined nicely the problems and a very nice solution on how to do this in this blog post. Thank you sir, for doing it right and sharing it with the world.

These worked beautifully until we tried to do a deployment. We pushed our app_offline.htm file to take the site offline, and instead of the nicely designed "Site undergoing maintenance" page, we saw this piece of junk:

The service is unavailable

The service is unavailable

Well, that's fantastic. After some troubleshooting we realized if we turned off httpErrors:

<httpErrors errorMode="Off" existingResponse="Replace">

The app_offline.htm page would work. How interesting? It seems that error codes not handled in this httpErrors section just output the default HTTP status code message. In this case, 503: The service is unavailable.

So, we can simply just handle 503 errors here:

<httpErrors errorMode="Custom" existingResponse="Replace">
    <remove statusCode="404"/>
    <error statusCode="404" path="404.html" responseMode="File" />
    <remove statusCode="500"/>
    <error statusCode="500" path="500.html" responseMode="File" />
    <remove statusCode="503"/>
    <error statusCode="503" path="app_offline.htm" responseMode="File" /> 

In theory, the only time a 503 is returned is when the app_offline.htm is present, so this works beautifully for us. Hope it works for you too!

Cheers, Rich
By Richard Rout
Only used for Gravatar avatar.

I am a chronic Googler. I Google more than is probably good for me. But sometimes I find myself really wanting to use Bing to do a search. Whenever I do though, the results are always sub par.

This is a big problem for me, so I came up with a solution which improves Bings search results automatically for you.

Go download it at the Chrome Web Store now!

Cheers, Rich
By Richard Rout
Only used for Gravatar avatar.

I've only made three posts here so far and already I've lost a bunch of posts due to my session timing out, or me accidentally brining the server down mid post. Needless to say I think it's time I did something about this because there are few things worse than doing a whole bunch of work and then having it deleted in an instant. So here goes!

The solution could involve submitting to the server every so often to update an unpublished temporary post, but that relies on the internet connection. So I guess we could utilize local storage? How about using good old cookies? It was a great idea. I had this working too until I tried saving a fairly large post and the cookies would refuse to update the cookie. There has to be something else... 

After a quick searching around I discovered localStorage. This stuff is amazing! You just use it as a javascript object to save strings:

// Save the subject
localStorage.savedSubject = "How to not lose your blog post";

// Later on - recover the subject

It appears you can only save strings in the objects. But lucky for JavaScript you can serialize and deserialize objects at will:

// Save the post
var savedBlogPost = {
 Subject: "How not to lose your blog post",
 Body: "I've only made about..."
localStorage.savedPost = JSON.stringify(savedBlogPost);

// Later on - recover the post
var recoveredBlogPost = JSON.parse(localStorage.savedPost);

So what's the down side? It's not in a cookie so it isn't sent to the server at all. That's fine though, we can get around that.

What we do is when you submit your form to add or update the blog post, we create a cookie that says "there is temporary data saved" and at that point we store the post data into a localStorage variable.

$('form').submit(function () { 
    utils.createCookieAndLocalStorage('postTempData', { 
        Subject: $('#Subject').val(), 
        Body: $('#Body').val()
    return true; 

On the server side, after the changes are saved successfully we remove the cookie postTempData that indicates the temporary saved data. This completes the success scenario.

For the fail scenario, we imagine the server never gets the call to save the post, or there is an error saving the post. When we recover from the error (by logging out, restarting browser or whatever) we go back to the "make a blog post page" and a check is performed to see if the temporary saved data indicator cookie exists. If it does then we pull the data out of the cookie and place it into the form. If it doesn't then we just ignore whatever may be in the localStorage variable.

$(function() {
    var data = utils.getLocalStorageIfCookie('postTempData');
    if (data) {

        // Notify user that the post was restored
        $('#restoreWarning').show().click(function () {
            // Clear cookie and local storage data when restore is cancelled

The cookie utils code looks like this:

var utils = (function() { 
    this.cookieLocalStorageIndicator = "__localStorage"; 

    this.createCookieAndLocalStorage = function (name, value, days) { 
        if (value != null) {
            value = JSON.stringify(value); 
            localStorage.setItem(name, value); 
            value = utils.cookieLocalStorageIndicator;

        var exdate = new Date(); 
        exdate.setDate(exdate.getDate() + days);
        document.cookie = name + "=" + escape(value) + "; path=/" + ((days == null) ? "" : "; expires=" + exdate.toUTCString()); 

    this.getLocalStorageIfCookie = function (name) {
        // ridiculous looking code to get the cookie value
        var c_value = document.cookie;
        var c_start = c_value.indexOf(" " + name + "="); 
        c_start = c_start == -1 ? c_value.indexOf(name + "=") : c_start; 
        if (c_start == -1) c_value = null; 
        else { 
            c_start = c_value.indexOf("=", c_start) + 1; 
            var c_end = c_value.indexOf(";", c_start);
            c_value = unescape(c_value.substring(c_start, c_end == -1 ? c_value.length : c_end)); 

        // if the cookie is in local storage, grab it from there
        if (c_value == utils.cookieLocalStorageIndicator) {
            c_value = localStorage.getItem(name);
        } else { 
            // otherwise, remove the item from local storage

        try {  c_value = JSON.parse(c_value);  } catch (err) {   } 
        return c_value; 
    return this; 

So that's it. I should never lose a blog post again... in theory. I have so much faith in this system I am going to hit "Submit" now without copying this post...

I lied, I totally copied it.

Cheers, Rich
By Richard Rout
Only used for Gravatar avatar.

I thought a lot about putting comments on this site. The main question is "Do I go pre-built or build my own?". I built my own, but that doesn't mean you should too. It really depends on your preferences and willingness to spend time on making your own and maintaining it. Here are the pros for going with a pre-built system such as Disqus;

  1. It just works out of the box
  2. Users are familiar with it and may already have an account
  3. Spam filtering is built in

Here are the cons (and ultimately why I decided to build my own):

  1. The data is not owned by you
  2. You might not be able to make the changes you want
  3. It relies on an external system which can go down

Number 1 and 2 are the deciding factors for me. I like control and I can't do that with an external system. So here's how I did it myself - it's fairly simple and hopefully it can help someone make their own decision on this matter.

The server side code is pretty trivial and just reads and inserts into a database, so I won't bore you with that. I went with a JavaScript heavy implementation, I had thought about using Knockout JS but I'm not currently using it on the site and can't justify a 14kb library of awesomeness just for this one small feature. So I went with just jQuery, and these are the two main functions for the comment system.

blog.loadComments = function (node) { 
   if (node.children('form').is(':visible')) { 
   } else { 
         url: "/Blog/Comments/" + node.data('id'), 
         method: 'get' 
      }).done(function(data) { 
         blog.displayComments(node, data); 
blog.displayComments = function (node, data) { 
   for (var i = 0; i < data.length; i++) { 
      var comment = data[i]; 
            .append($('<img />').addClass("thumbnail").attr('src', comment.ProfilePicture).attr('alt', comment.Name).attr('title', comment.Name)) 

So that's it, really. They are fairly self explanatory functions, blog.loadComments is responsible for pulling the comments from the database and calling blog.displayComments which is responsible for iterating through the data and filling the correct element on the site. We have one other small piece that kicks off the whole thing:

// Comments loading code 
var commentNodes = $('.post .post-comments'); 
if (commentNodes.length == 1) { 
   // load comments if there is only one 
} else if (commentNodes.length > 1) { 
   // attach the click to the a 
   $('a', commentNodes).click(function () { 

If we are just looking at one post, then the comments will pull from the database and display automatically. However if we are looking at page with multiple posts on it (i.e. the home page) the comments will not load, instead we just attach a click even to the comments button to bring them up.

Cheers, Rich
By Richard Rout
Only used for Gravatar avatar.

The kncokout js library is amazing. It's capable of making even the most complex JavaScript applications super simple and robust. Obviously it's not ideal in al situations, and there are a bunch of libraries that do similar things, but this one is incredible and it scales so well.

Enter Knockout!

We're now making a fairly large ASP.NET MVC application and we need a nice way of displaying and saving arrays of objects in our forms. Obviously there is no standard MVC EditorFor for doing this, so we looked at ways to make our own.

"Wouldn't it be cool if we didn't have to worry about arrays of JSON objects, having to send them to the page, edit them and then post them back?" Said one developer.
"That would be super cool... but how?" Said another.

Enter knockout! 

We can do this with a knockout binding. And we don't have to worry about setting model data to JavaScript objects, editing them or posting them back. That can all be handled. Here's how:

First we have an HTML element that uses the binding

<div data-bind="hiddens: { data: @Json.Encode(model.ComplicatedArray), name: 'ComplicatedArray' }">

Are you with me so far? Then we define our binding that looks a little something like this:

ko.bindingHandlers.hiddens = { 
    update: function(element, valueAccessor) { 
        var value = ko.mapping.toJS(valueAccessor().data); 
        $(element).empty().append(objectToHiddenDom(value, valueAccessor().name)); 

function objectToHiddenDom(value, namePrefix, hiddenArray) { 
    if (!hiddenArray) { 
        hiddenArray = []; 
    if (utils.isArray(value)) { 
        for (var i = 0; i < value.length; i++) { 
            utils.objectToHiddenDom(value[i], namePrefix + '[' + i + ']', hiddenArray); 
    } else if (utils.isObject(value)) { 
        for (var key in value) { 
            utils.objectToHiddenDom(value[key], namePrefix + '.' + key, hiddenArray); 
    } else { 
        // simple type, push to array 
        hiddenArray.push($('<input />').attr('type', 'hidden').attr('name', namePrefix).val(value)); 
    return hiddenArray; 

When you run it your DOM might end up with a little something like this:

<div data-bind="hiddens: { data: [], name: 'ComplicatedArray' }">
    <input type="hidden" name="ComplicatedArray[0].Id" value="_1367629733949">
    <input type="hidden" name="ComplicatedArray[0].Name" value="Thing 1">
    <input type="hidden" name="ComplicatedArray[1].Id" value="_1367629738172">
    <input type="hidden" name="ComplicatedArray[1].Name" value="Thing 2">
    <input type="hidden" name="ComplicatedArray[2].Id" value="_1367629742061">
    <input type="hidden" name="ComplicatedArray[2].Name" value="Another Thing">

You don't have to care about what's inside the object, it doesn't even have to be an array. It figures all that out. This code does, however, have some performance issues with very very very large objects because it empties the DOM and recreates it every time. If anyone has any suggestions about this I would love to hear them.

Cheers, Rich
By Richard Rout
Only used for Gravatar avatar.

As a programmer, the first thing you learn is Hello World applications. So it would make sense that every blog should start with a hello world post. Here is a hello world in javascript

document.write("Hello World")

You may notice that this blog is very basic, and you would be correct. The features are coming, but I want to do it a little differently. I want to share each feature as I create it. Each update will be accompanied by a new post, and maybe even a video that will give a little detail on the development of this blog and any cool things I find along the way.

This blog is written in ASP.NET MVC, I'm using Bootstrap for my CSS template and I will be making heavy use of jQuery in future features. I'm using AWS Elastic Beanstalk to deploy and host this application, and here is a short video explaining how I do that.


Thanks for reading my blog, and feel free to leave comments (when I have them).

Cheers, Rich
By Richard Rout
Only used for Gravatar avatar.