(function(){

  // A shim for non ES5 supporting browsers, like PhantomJS. Lovingly inspired by:
  // http://www.angrycoding.com/2011/09/to-bind-or-not-to-bind-that-is-in.html
  if (!('bind' in Function.prototype)) {
    Function.prototype.bind = function() {
      var funcObj = this;
      var extraArgs = Array.prototype.slice.call(arguments);
      var thisObj = extraArgs.shift();
      return function() {
        return funcObj.apply(thisObj, extraArgs.concat(Array.prototype.slice.call(arguments)));
      };
    };
  }

  function isFileReady(readyState) {
    // Check to see if any of the ways a file can be ready are available as properties on the file's element
    return (!readyState || readyState == 'loaded' || readyState == 'complete' || readyState == 'uninitialized')
  }

  function shimMochaProcess(M) {
    // Mocha needs a process.stdout.write in order to change the cursor position.
    M.process = M.process || {}
    M.process.stdout = M.process.stdout || process.stdout
    M.process.stdout.write = function(s) { window.callPhantom({ stdout: s }) }
    window.callPhantom({ getColWith: true })
  }

  function shimMochaInstance(m) {
    var origRun = m.run, origUi = m.ui
    m.ui = function() {
      var retval = origUi.apply(mocha, arguments)
      window.callPhantom({ configureMocha: true })
      m.reporter = function() {}
      return retval
    }
    m.run = function() {
      window.callPhantom({ testRunStarted: m.suite.suites.length })
      m.runner = origRun.apply(mocha, arguments)
      if (m.runner.stats && m.runner.stats.end) {
        window.callPhantom({ testRunEnded: m.runner })
      } else {
        m.runner.on('end', function() {
          window.callPhantom({ testRunEnded: m.runner })
        })
      }
      return m.runner
    }
  }

  Object.defineProperty(window, 'checkForMocha', {
    value: function() {
      var scriptTags = document.querySelectorAll('script'),
          mochaScript = Array.prototype.filter.call(scriptTags, function(s) {
            var src = s.getAttribute('src')
            return src && src.match(/mocha\.js$/)
          })[0]

      if (mochaScript) {
        mochaScript.onreadystatechange = mochaScript.onload = function () {
          if (isFileReady(mochaScript.readyState)) {
            initMochaPhantomJS()
          }
        }
      }
    }
  })

  if ('mozInnerScreenX' in window) {
    // in slimerjs, we can stub out a setter to shim Mocha. phantomjs 2 fails
    // to allow the property to be reconfigured...
    Object.defineProperty(window, 'mocha', {
      get: function() { return undefined },
      set: function(m) {
        shimMochaInstance(m)
        delete window.mocha
        window.mocha = m
      },
      configurable: true
    })

    Object.defineProperty(window, 'Mocha', {
      get: function() { return undefined },
      set: function(m) {
        delete window.Mocha
        window.Mocha = m
        shimMochaProcess(m)
      },
      configurable: true
    })
  } else {
    Object.defineProperty(window, 'initMochaPhantomJS', {
      value: function () {
        shimMochaProcess(Mocha)
        shimMochaInstance(mocha)
        delete window.initMochaPhantomJS
      },
      configurable: true
    })
  }

  // Mocha needs the formating feature of console.log so copy node's format function and
  // monkey-patch it into place. This code is copied from node's, links copyright applies.
  // https://github.com/joyent/node/blob/master/lib/util.js
  if (!console.format) {
    console.format = function(f) {
      if (typeof f !== 'string') {
        return Array.prototype.map.call(arguments, function(arg) {
          try {
            return JSON.stringify(arg)
          }
          catch (_) {
            return '[Circular]'
          }
        }).join(' ')
      }
      var i = 1;
      var args = arguments;
      var len = args.length;
      var str = String(f).replace(/%[sdj%]/g, function(x) {
        if (x === '%%') return '%';
        if (i >= len) return x;
        switch (x) {
          case '%s': return String(args[i++]);
          case '%d': return Number(args[i++]);
          case '%j':
            try {
              return JSON.stringify(args[i++]);
            } catch (_) {
              return '[Circular]';
            }
          default:
            return x;
        }
      });
      for (var x = args[i]; i < len; x = args[++i]) {
        if (x === null || typeof x !== 'object') {
          str += ' ' + x;
        } else {
          str += ' ' + JSON.stringify(x);
        }
      }
      return str;
    };
    var origError = console.error;
    console.error = function(){ origError.call(console, console.format.apply(console, arguments)); };
    var origLog = console.log;
    console.log = function(){ origLog.call(console, console.format.apply(console, arguments)); };
  }

})();

@@ -13,205 +13,57 @@
 %0A%0A  
-// A shim for non ES5 supporting browsers, like PhantomJS. Lovingly inspired by:%0A  // http://www.angrycoding.com/2011/09/to-bind-or-not-to-bind-that-is-in.html%0A  if (!('bind' in Function.prototype)
+if (typeof Function.prototype.bind !== 'function'
 ) %7B%0A
@@ -104,38 +104,20 @@
 tion
-() %7B%0A      var funcObj = this;
+ bind(obj) %7B
 %0A   
@@ -123,22 +123,17 @@
     var 
-extraA
+a
 rgs = Ar
@@ -170,62 +170,79 @@
 ents
-);
+, 1),
 %0A      
-var thisObj = extraArgs.shift();%0A      return
+  self = this,%0A        nop = function() %7B%7D,%0A        bound =
  fun
@@ -263,55 +263,110 @@
     
+  
 return 
-funcObj.apply(thisObj, extraArgs.concat(
+self.apply(%0A            this instanceof nop ? this : (obj %7C%7C %7B%7D), args.concat(%0A              
 Arra
@@ -402,27 +402,146 @@
 nts)
-));%0A
+%0A            )%0A          )%0A  
       %7D
-;
 %0A    
+  nop.prototype = this.prototype %7C%7C %7B%7D%0A      bound.prototype = new nop()%0A      return bound%0A    
 %7D
-;
 %0A  %7D

Update Function#bind polyfil to be up to spec