docs: function shimES5() {
      var has = Object.prototype.hasOwnProperty
  
      // ES5 15.2.3.6
      if (!Object.defineProperty || ie === 8) { // ie8
        Object.defineProperty = function(object, property, descriptor) {
          if (typeof descriptor == "object" && object.__defineGetter__) {
            if (has.call(descriptor, "value")) {
              if (!object.__lookupGetter__(property) && !object.__lookupSetter__(property)) {
                // data property defined and no pre-existing accessors
                object[property] = descriptor.value
              }
              if (has.call(descriptor, "get") || has.call(descriptor, "set")) {
                // descriptor has a value property but accessor already exists
                throw new TypeError("Object doesn't support this action")
              }
            }
            // fail silently if "writable", "enumerable", or "configurable"
            // are requested but not supported
            else if (typeof descriptor.get == "function") {
              object.__defineGetter__(property, descriptor.get)
            }
            if (typeof descriptor.set == "function") {
              object.__defineSetter__(property, descriptor.set)
            }
          }
          return object
        }
      }
  
      // ES5 15.2.3.14
      // http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation
      if (!Object.keys) { // ie8
        (function() {
          var hasDontEnumBug = true,
            dontEnums = [
              'toString',
              'toLocaleString',
              'valueOf',
              'hasOwnProperty',
              'isPrototypeOf',
              'propertyIsEnumerable',
              'constructor'
            ],
            dontEnumsLength = dontEnums.length
  
          for (var key in {"toString": null}) {
            hasDontEnumBug = false
          }
  
          Object.keys = function (object) {
  
            if (
              typeof object !== "object" && typeof object !== "function"
              || object === null
            )
              throw new TypeError("Object.keys called on a non-object")
  
            var keys = []
            for (var name in object) {
              if (has.call(object, name)) {
                keys.push(name)
              }
            }
  
            if (hasDontEnumBug) {
              for (var i = 0, ii = dontEnumsLength; i < ii; i++) {
                var dontEnum = dontEnums[i]
                if (has.call(object, dontEnum)) {
                  keys.push(dontEnum)
                }
              }
            }
  
            return keys
          }
        }())
      } // Object.keys
  
      //
      // Array
      // =====
      //
  
      // ES5 15.4.3.2
      if (!Array.isArray) {
        Array.isArray = function(obj) {
          return Object.prototype.toString.call(obj) == "[object Array]"
        }
      }
  
      // ES5 15.4.4.18
      if (!Array.prototype.forEach) { // ie8
        Array.prototype.forEach =  function(block, thisObject) {
          var len = this.length >>> 0
          for (var i = 0; i < len; i++) {
            if (i in this) {
              block.call(thisObject, this[i], i, this)
            }
          }
        }
      }
  
      // ES5 15.4.4.19
      // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/map
      if (!Array.prototype.map) { // ie8
        Array.prototype.map = function(fun /*, thisp*/) {
          var len = this.length >>> 0
          if (typeof fun != "function") {
            throw new TypeError()
          }
  
          var res = new Array(len)
          var thisp = arguments[1]
          for (var i = 0; i < len; i++) {
            if (i in this) {
              res[i] = fun.call(thisp, this[i], i, this)
            }
          }
  
          return res
        }
      }
  
      // ES5 15.4.4.20
      if (!Array.prototype.filter) { // ie8
        Array.prototype.filter = function (block /*, thisp */) {
          var values = []
            , thisp = arguments[1]
          for (var i = 0; i < this.length; i++) {
            if (block.call(thisp, this[i])) {
              values.push(this[i])
            }
          }
          return values
        }
      }
  
      // ES5 15.4.4.21
      // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduce
      if (!Array.prototype.reduce) { // ie8
        Array.prototype.reduce = function(fun /*, initial*/) {
          var len = this.length >>> 0
          if (typeof fun != "function") {
            throw new TypeError()
          }
  
          // no value to return if no initial value and an empty array
          if (len == 0 && arguments.length == 1) {
            throw new TypeError()
          }
  
          var i = 0
          if (arguments.length >= 2) {
            var rv = arguments[1]
          } else {
            do {
              if (i in this) {
                rv = this[i++]
                break
              }
  
              // if array contains no values, no initial value to return
              if (++i >= len) {
                throw new TypeError()
              }
            } while (true)
          }
  
          for (; i < len; i++) {
            if (i in this) {
              rv = fun.call(null, rv, this[i], i, this)
            }
          }
  
          return rv
        }
      } // Array.prototype.reduce
    }