Merge "objectcache: Actually unserialize integers as integers in RedisBagOStuff"
[mediawiki.git] / resources / lib / es5-shim / es5-shim.js
blob02048c0a50d6043d02c221cbce48e1038a072f47
1 /*!
2  * https://github.com/es-shims/es5-shim
3  * @license es5-shim Copyright 2009-2014 by contributors, MIT License
4  * see https://github.com/es-shims/es5-shim/blob/master/LICENSE
5  */
7 // vim: ts=4 sts=4 sw=4 expandtab
9 //Add semicolon to prevent IIFE from being passed as argument to concated code.
12 // UMD (Universal Module Definition)
13 // see https://github.com/umdjs/umd/blob/master/returnExports.js
14 (function (root, factory) {
15     if (typeof define === 'function' && define.amd) {
16         // AMD. Register as an anonymous module.
17         define(factory);
18     } else if (typeof exports === 'object') {
19         // Node. Does not work with strict CommonJS, but
20         // only CommonJS-like enviroments that support module.exports,
21         // like Node.
22         module.exports = factory();
23     } else {
24         // Browser globals (root is window)
25         root.returnExports = factory();
26     }
27 }(this, function () {
29 /**
30  * Brings an environment as close to ECMAScript 5 compliance
31  * as is possible with the facilities of erstwhile engines.
32  *
33  * Annotated ES5: http://es5.github.com/ (specific links below)
34  * ES5 Spec: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf
35  * Required reading: http://javascriptweblog.wordpress.com/2011/12/05/extending-javascript-natives/
36  */
38 // Shortcut to an often accessed properties, in order to avoid multiple
39 // dereference that costs universally.
40 var ArrayPrototype = Array.prototype;
41 var ObjectPrototype = Object.prototype;
42 var FunctionPrototype = Function.prototype;
43 var StringPrototype = String.prototype;
44 var NumberPrototype = Number.prototype;
45 var _Array_slice_ = ArrayPrototype.slice;
46 var array_splice = ArrayPrototype.splice;
47 var array_push = ArrayPrototype.push;
48 var array_unshift = ArrayPrototype.unshift;
49 var call = FunctionPrototype.call;
51 // Having a toString local variable name breaks in Opera so use _toString.
52 var _toString = ObjectPrototype.toString;
54 var isFunction = function (val) {
55     return ObjectPrototype.toString.call(val) === '[object Function]';
57 var isRegex = function (val) {
58     return ObjectPrototype.toString.call(val) === '[object RegExp]';
60 var isArray = function isArray(obj) {
61     return _toString.call(obj) === "[object Array]";
63 var isString = function isString(obj) {
64     return _toString.call(obj) === "[object String]";
66 var isArguments = function isArguments(value) {
67     var str = _toString.call(value);
68     var isArgs = str === '[object Arguments]';
69     if (!isArgs) {
70         isArgs = !isArray(str)
71             && value !== null
72             && typeof value === 'object'
73             && typeof value.length === 'number'
74             && value.length >= 0
75             && isFunction(value.callee);
76     }
77     return isArgs;
80 var supportsDescriptors = Object.defineProperty && (function () {
81     try {
82         Object.defineProperty({}, 'x', {});
83         return true;
84     } catch (e) { /* this is ES3 */
85         return false;
86     }
87 }());
89 // Define configurable, writable and non-enumerable props
90 // if they don't exist.
91 var defineProperty;
92 if (supportsDescriptors) {
93     defineProperty = function (object, name, method, forceAssign) {
94         if (!forceAssign && (name in object)) { return; }
95         Object.defineProperty(object, name, {
96             configurable: true,
97             enumerable: false,
98             writable: true,
99             value: method
100         });
101     };
102 } else {
103     defineProperty = function (object, name, method, forceAssign) {
104         if (!forceAssign && (name in object)) { return; }
105         object[name] = method;
106     };
108 var defineProperties = function (object, map, forceAssign) {
109     for (var name in map) {
110         if (ObjectPrototype.hasOwnProperty.call(map, name)) {
111           defineProperty(object, name, map[name], forceAssign);
112         }
113     }
117 // Util
118 // ======
121 // ES5 9.4
122 // http://es5.github.com/#x9.4
123 // http://jsperf.com/to-integer
125 function toInteger(n) {
126     n = +n;
127     if (n !== n) { // isNaN
128         n = 0;
129     } else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0)) {
130         n = (n > 0 || -1) * Math.floor(Math.abs(n));
131     }
132     return n;
135 function isPrimitive(input) {
136     var type = typeof input;
137     return (
138         input === null ||
139         type === "undefined" ||
140         type === "boolean" ||
141         type === "number" ||
142         type === "string"
143     );
146 function toPrimitive(input) {
147     var val, valueOf, toStr;
148     if (isPrimitive(input)) {
149         return input;
150     }
151     valueOf = input.valueOf;
152     if (isFunction(valueOf)) {
153         val = valueOf.call(input);
154         if (isPrimitive(val)) {
155             return val;
156         }
157     }
158     toStr = input.toString;
159     if (isFunction(toStr)) {
160         val = toStr.call(input);
161         if (isPrimitive(val)) {
162             return val;
163         }
164     }
165     throw new TypeError();
168 // ES5 9.9
169 // http://es5.github.com/#x9.9
170 var toObject = function (o) {
171     if (o == null) { // this matches both null and undefined
172         throw new TypeError("can't convert " + o + " to object");
173     }
174     return Object(o);
177 var ToUint32 = function ToUint32(x) {
178     return x >>> 0;
182 // Function
183 // ========
186 // ES-5 15.3.4.5
187 // http://es5.github.com/#x15.3.4.5
189 function Empty() {}
191 defineProperties(FunctionPrototype, {
192     bind: function bind(that) { // .length is 1
193         // 1. Let Target be the this value.
194         var target = this;
195         // 2. If IsCallable(Target) is false, throw a TypeError exception.
196         if (!isFunction(target)) {
197             throw new TypeError("Function.prototype.bind called on incompatible " + target);
198         }
199         // 3. Let A be a new (possibly empty) internal list of all of the
200         //   argument values provided after thisArg (arg1, arg2 etc), in order.
201         // XXX slicedArgs will stand in for "A" if used
202         var args = _Array_slice_.call(arguments, 1); // for normal call
203         // 4. Let F be a new native ECMAScript object.
204         // 11. Set the [[Prototype]] internal property of F to the standard
205         //   built-in Function prototype object as specified in 15.3.3.1.
206         // 12. Set the [[Call]] internal property of F as described in
207         //   15.3.4.5.1.
208         // 13. Set the [[Construct]] internal property of F as described in
209         //   15.3.4.5.2.
210         // 14. Set the [[HasInstance]] internal property of F as described in
211         //   15.3.4.5.3.
212         var binder = function () {
214             if (this instanceof bound) {
215                 // 15.3.4.5.2 [[Construct]]
216                 // When the [[Construct]] internal method of a function object,
217                 // F that was created using the bind function is called with a
218                 // list of arguments ExtraArgs, the following steps are taken:
219                 // 1. Let target be the value of F's [[TargetFunction]]
220                 //   internal property.
221                 // 2. If target has no [[Construct]] internal method, a
222                 //   TypeError exception is thrown.
223                 // 3. Let boundArgs be the value of F's [[BoundArgs]] internal
224                 //   property.
225                 // 4. Let args be a new list containing the same values as the
226                 //   list boundArgs in the same order followed by the same
227                 //   values as the list ExtraArgs in the same order.
228                 // 5. Return the result of calling the [[Construct]] internal
229                 //   method of target providing args as the arguments.
231                 var result = target.apply(
232                     this,
233                     args.concat(_Array_slice_.call(arguments))
234                 );
235                 if (Object(result) === result) {
236                     return result;
237                 }
238                 return this;
240             } else {
241                 // 15.3.4.5.1 [[Call]]
242                 // When the [[Call]] internal method of a function object, F,
243                 // which was created using the bind function is called with a
244                 // this value and a list of arguments ExtraArgs, the following
245                 // steps are taken:
246                 // 1. Let boundArgs be the value of F's [[BoundArgs]] internal
247                 //   property.
248                 // 2. Let boundThis be the value of F's [[BoundThis]] internal
249                 //   property.
250                 // 3. Let target be the value of F's [[TargetFunction]] internal
251                 //   property.
252                 // 4. Let args be a new list containing the same values as the
253                 //   list boundArgs in the same order followed by the same
254                 //   values as the list ExtraArgs in the same order.
255                 // 5. Return the result of calling the [[Call]] internal method
256                 //   of target providing boundThis as the this value and
257                 //   providing args as the arguments.
259                 // equiv: target.call(this, ...boundArgs, ...args)
260                 return target.apply(
261                     that,
262                     args.concat(_Array_slice_.call(arguments))
263                 );
265             }
267         };
269         // 15. If the [[Class]] internal property of Target is "Function", then
270         //     a. Let L be the length property of Target minus the length of A.
271         //     b. Set the length own property of F to either 0 or L, whichever is
272         //       larger.
273         // 16. Else set the length own property of F to 0.
275         var boundLength = Math.max(0, target.length - args.length);
277         // 17. Set the attributes of the length own property of F to the values
278         //   specified in 15.3.5.1.
279         var boundArgs = [];
280         for (var i = 0; i < boundLength; i++) {
281             boundArgs.push("$" + i);
282         }
284         // XXX Build a dynamic function with desired amount of arguments is the only
285         // way to set the length property of a function.
286         // In environments where Content Security Policies enabled (Chrome extensions,
287         // for ex.) all use of eval or Function costructor throws an exception.
288         // However in all of these environments Function.prototype.bind exists
289         // and so this code will never be executed.
290         var bound = Function("binder", "return function (" + boundArgs.join(",") + "){return binder.apply(this,arguments)}")(binder);
292         if (target.prototype) {
293             Empty.prototype = target.prototype;
294             bound.prototype = new Empty();
295             // Clean up dangling references.
296             Empty.prototype = null;
297         }
299         // TODO
300         // 18. Set the [[Extensible]] internal property of F to true.
302         // TODO
303         // 19. Let thrower be the [[ThrowTypeError]] function Object (13.2.3).
304         // 20. Call the [[DefineOwnProperty]] internal method of F with
305         //   arguments "caller", PropertyDescriptor {[[Get]]: thrower, [[Set]]:
306         //   thrower, [[Enumerable]]: false, [[Configurable]]: false}, and
307         //   false.
308         // 21. Call the [[DefineOwnProperty]] internal method of F with
309         //   arguments "arguments", PropertyDescriptor {[[Get]]: thrower,
310         //   [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false},
311         //   and false.
313         // TODO
314         // NOTE Function objects created using Function.prototype.bind do not
315         // have a prototype property or the [[Code]], [[FormalParameters]], and
316         // [[Scope]] internal properties.
317         // XXX can't delete prototype in pure-js.
319         // 22. Return F.
320         return bound;
321     }
324 // _Please note: Shortcuts are defined after `Function.prototype.bind` as we
325 // us it in defining shortcuts.
326 var owns = call.bind(ObjectPrototype.hasOwnProperty);
328 // If JS engine supports accessors creating shortcuts.
329 var defineGetter;
330 var defineSetter;
331 var lookupGetter;
332 var lookupSetter;
333 var supportsAccessors;
334 if ((supportsAccessors = owns(ObjectPrototype, "__defineGetter__"))) {
335     defineGetter = call.bind(ObjectPrototype.__defineGetter__);
336     defineSetter = call.bind(ObjectPrototype.__defineSetter__);
337     lookupGetter = call.bind(ObjectPrototype.__lookupGetter__);
338     lookupSetter = call.bind(ObjectPrototype.__lookupSetter__);
342 // Array
343 // =====
346 // ES5 15.4.4.12
347 // http://es5.github.com/#x15.4.4.12
348 var spliceNoopReturnsEmptyArray = (function () {
349     var a = [1, 2];
350     var result = a.splice();
351     return a.length === 2 && isArray(result) && result.length === 0;
352 }());
353 defineProperties(ArrayPrototype, {
354     // Safari 5.0 bug where .splice() returns undefined
355     splice: function splice(start, deleteCount) {
356         if (arguments.length === 0) {
357             return [];
358         } else {
359             return array_splice.apply(this, arguments);
360         }
361     }
362 }, spliceNoopReturnsEmptyArray);
364 var spliceWorksWithEmptyObject = (function () {
365     var obj = {};
366     ArrayPrototype.splice.call(obj, 0, 0, 1);
367     return obj.length === 1;
368 }());
369 var omittingSecondSpliceArgIsNoop = [1].splice(0).length === 0;
370 defineProperties(ArrayPrototype, {
371     splice: function splice(start, deleteCount) {
372         if (arguments.length === 0) { return []; }
373         var args = arguments;
374         this.length = Math.max(toInteger(this.length), 0);
375         if (arguments.length > 0 && typeof deleteCount !== 'number') {
376             args = _Array_slice_.call(arguments);
377             if (args.length < 2) {
378                 args.push(toInteger(deleteCount));
379             } else {
380                 args[1] = toInteger(deleteCount);
381             }
382         }
383         return array_splice.apply(this, args);
384     }
385 }, !omittingSecondSpliceArgIsNoop || !spliceWorksWithEmptyObject);
387 // ES5 15.4.4.12
388 // http://es5.github.com/#x15.4.4.13
389 // Return len+argCount.
390 // [bugfix, ielt8]
391 // IE < 8 bug: [].unshift(0) === undefined but should be "1"
392 var hasUnshiftReturnValueBug = [].unshift(0) !== 1;
393 defineProperties(ArrayPrototype, {
394     unshift: function () {
395         array_unshift.apply(this, arguments);
396         return this.length;
397     }
398 }, hasUnshiftReturnValueBug);
400 // ES5 15.4.3.2
401 // http://es5.github.com/#x15.4.3.2
402 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/isArray
403 defineProperties(Array, { isArray: isArray });
405 // The IsCallable() check in the Array functions
406 // has been replaced with a strict check on the
407 // internal class of the object to trap cases where
408 // the provided function was actually a regular
409 // expression literal, which in V8 and
410 // JavaScriptCore is a typeof "function".  Only in
411 // V8 are regular expression literals permitted as
412 // reduce parameters, so it is desirable in the
413 // general case for the shim to match the more
414 // strict and common behavior of rejecting regular
415 // expressions.
417 // ES5 15.4.4.18
418 // http://es5.github.com/#x15.4.4.18
419 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/forEach
421 // Check failure of by-index access of string characters (IE < 9)
422 // and failure of `0 in boxedString` (Rhino)
423 var boxedString = Object("a");
424 var splitString = boxedString[0] !== "a" || !(0 in boxedString);
426 var properlyBoxesContext = function properlyBoxed(method) {
427     // Check node 0.6.21 bug where third parameter is not boxed
428     var properlyBoxesNonStrict = true;
429     var properlyBoxesStrict = true;
430     if (method) {
431         method.call('foo', function (_, __, context) {
432             if (typeof context !== 'object') { properlyBoxesNonStrict = false; }
433         });
435         method.call([1], function () {
436             'use strict';
437             properlyBoxesStrict = typeof this === 'string';
438         }, 'x');
439     }
440     return !!method && properlyBoxesNonStrict && properlyBoxesStrict;
443 defineProperties(ArrayPrototype, {
444     forEach: function forEach(fun /*, thisp*/) {
445         var object = toObject(this),
446             self = splitString && isString(this) ? this.split('') : object,
447             thisp = arguments[1],
448             i = -1,
449             length = self.length >>> 0;
451         // If no callback function or if callback is not a callable function
452         if (!isFunction(fun)) {
453             throw new TypeError(); // TODO message
454         }
456         while (++i < length) {
457             if (i in self) {
458                 // Invoke the callback function with call, passing arguments:
459                 // context, property value, property key, thisArg object
460                 // context
461                 fun.call(thisp, self[i], i, object);
462             }
463         }
464     }
465 }, !properlyBoxesContext(ArrayPrototype.forEach));
467 // ES5 15.4.4.19
468 // http://es5.github.com/#x15.4.4.19
469 // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/map
470 defineProperties(ArrayPrototype, {
471     map: function map(fun /*, thisp*/) {
472         var object = toObject(this),
473             self = splitString && isString(this) ? this.split('') : object,
474             length = self.length >>> 0,
475             result = Array(length),
476             thisp = arguments[1];
478         // If no callback function or if callback is not a callable function
479         if (!isFunction(fun)) {
480             throw new TypeError(fun + " is not a function");
481         }
483         for (var i = 0; i < length; i++) {
484             if (i in self) {
485                 result[i] = fun.call(thisp, self[i], i, object);
486             }
487         }
488         return result;
489     }
490 }, !properlyBoxesContext(ArrayPrototype.map));
492 // ES5 15.4.4.20
493 // http://es5.github.com/#x15.4.4.20
494 // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/filter
495 defineProperties(ArrayPrototype, {
496     filter: function filter(fun /*, thisp */) {
497         var object = toObject(this),
498             self = splitString && isString(this) ? this.split('') : object,
499             length = self.length >>> 0,
500             result = [],
501             value,
502             thisp = arguments[1];
504         // If no callback function or if callback is not a callable function
505         if (!isFunction(fun)) {
506             throw new TypeError(fun + " is not a function");
507         }
509         for (var i = 0; i < length; i++) {
510             if (i in self) {
511                 value = self[i];
512                 if (fun.call(thisp, value, i, object)) {
513                     result.push(value);
514                 }
515             }
516         }
517         return result;
518     }
519 }, !properlyBoxesContext(ArrayPrototype.filter));
521 // ES5 15.4.4.16
522 // http://es5.github.com/#x15.4.4.16
523 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/every
524 defineProperties(ArrayPrototype, {
525     every: function every(fun /*, thisp */) {
526         var object = toObject(this),
527             self = splitString && isString(this) ? this.split('') : object,
528             length = self.length >>> 0,
529             thisp = arguments[1];
531         // If no callback function or if callback is not a callable function
532         if (!isFunction(fun)) {
533             throw new TypeError(fun + " is not a function");
534         }
536         for (var i = 0; i < length; i++) {
537             if (i in self && !fun.call(thisp, self[i], i, object)) {
538                 return false;
539             }
540         }
541         return true;
542     }
543 }, !properlyBoxesContext(ArrayPrototype.every));
545 // ES5 15.4.4.17
546 // http://es5.github.com/#x15.4.4.17
547 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/some
548 defineProperties(ArrayPrototype, {
549     some: function some(fun /*, thisp */) {
550         var object = toObject(this),
551             self = splitString && isString(this) ? this.split('') : object,
552             length = self.length >>> 0,
553             thisp = arguments[1];
555         // If no callback function or if callback is not a callable function
556         if (!isFunction(fun)) {
557             throw new TypeError(fun + " is not a function");
558         }
560         for (var i = 0; i < length; i++) {
561             if (i in self && fun.call(thisp, self[i], i, object)) {
562                 return true;
563             }
564         }
565         return false;
566     }
567 }, !properlyBoxesContext(ArrayPrototype.some));
569 // ES5 15.4.4.21
570 // http://es5.github.com/#x15.4.4.21
571 // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduce
572 var reduceCoercesToObject = false;
573 if (ArrayPrototype.reduce) {
574     reduceCoercesToObject = typeof ArrayPrototype.reduce.call('es5', function (_, __, ___, list) { return list; }) === 'object';
576 defineProperties(ArrayPrototype, {
577     reduce: function reduce(fun /*, initial*/) {
578         var object = toObject(this),
579             self = splitString && isString(this) ? this.split('') : object,
580             length = self.length >>> 0;
582         // If no callback function or if callback is not a callable function
583         if (!isFunction(fun)) {
584             throw new TypeError(fun + " is not a function");
585         }
587         // no value to return if no initial value and an empty array
588         if (!length && arguments.length === 1) {
589             throw new TypeError("reduce of empty array with no initial value");
590         }
592         var i = 0;
593         var result;
594         if (arguments.length >= 2) {
595             result = arguments[1];
596         } else {
597             do {
598                 if (i in self) {
599                     result = self[i++];
600                     break;
601                 }
603                 // if array contains no values, no initial value to return
604                 if (++i >= length) {
605                     throw new TypeError("reduce of empty array with no initial value");
606                 }
607             } while (true);
608         }
610         for (; i < length; i++) {
611             if (i in self) {
612                 result = fun.call(void 0, result, self[i], i, object);
613             }
614         }
616         return result;
617     }
618 }, !reduceCoercesToObject);
620 // ES5 15.4.4.22
621 // http://es5.github.com/#x15.4.4.22
622 // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduceRight
623 var reduceRightCoercesToObject = false;
624 if (ArrayPrototype.reduceRight) {
625     reduceRightCoercesToObject = typeof ArrayPrototype.reduceRight.call('es5', function (_, __, ___, list) { return list; }) === 'object';
627 defineProperties(ArrayPrototype, {
628     reduceRight: function reduceRight(fun /*, initial*/) {
629         var object = toObject(this),
630             self = splitString && isString(this) ? this.split('') : object,
631             length = self.length >>> 0;
633         // If no callback function or if callback is not a callable function
634         if (!isFunction(fun)) {
635             throw new TypeError(fun + " is not a function");
636         }
638         // no value to return if no initial value, empty array
639         if (!length && arguments.length === 1) {
640             throw new TypeError("reduceRight of empty array with no initial value");
641         }
643         var result, i = length - 1;
644         if (arguments.length >= 2) {
645             result = arguments[1];
646         } else {
647             do {
648                 if (i in self) {
649                     result = self[i--];
650                     break;
651                 }
653                 // if array contains no values, no initial value to return
654                 if (--i < 0) {
655                     throw new TypeError("reduceRight of empty array with no initial value");
656                 }
657             } while (true);
658         }
660         if (i < 0) {
661             return result;
662         }
664         do {
665             if (i in self) {
666                 result = fun.call(void 0, result, self[i], i, object);
667             }
668         } while (i--);
670         return result;
671     }
672 }, !reduceRightCoercesToObject);
674 // ES5 15.4.4.14
675 // http://es5.github.com/#x15.4.4.14
676 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf
677 var hasFirefox2IndexOfBug = [0, 1].indexOf(1, 2) !== -1;
678 defineProperties(ArrayPrototype, {
679     indexOf: function indexOf(sought /*, fromIndex */ ) {
680         var self = splitString && isString(this) ? this.split('') : toObject(this),
681             length = self.length >>> 0;
683         if (!length) {
684             return -1;
685         }
687         var i = 0;
688         if (arguments.length > 1) {
689             i = toInteger(arguments[1]);
690         }
692         // handle negative indices
693         i = i >= 0 ? i : Math.max(0, length + i);
694         for (; i < length; i++) {
695             if (i in self && self[i] === sought) {
696                 return i;
697             }
698         }
699         return -1;
700     }
701 }, hasFirefox2IndexOfBug);
703 // ES5 15.4.4.15
704 // http://es5.github.com/#x15.4.4.15
705 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/lastIndexOf
706 var hasFirefox2LastIndexOfBug = [0, 1].lastIndexOf(0, -3) !== -1;
707 defineProperties(ArrayPrototype, {
708     lastIndexOf: function lastIndexOf(sought /*, fromIndex */) {
709         var self = splitString && isString(this) ? this.split('') : toObject(this),
710             length = self.length >>> 0;
712         if (!length) {
713             return -1;
714         }
715         var i = length - 1;
716         if (arguments.length > 1) {
717             i = Math.min(i, toInteger(arguments[1]));
718         }
719         // handle negative indices
720         i = i >= 0 ? i : length - Math.abs(i);
721         for (; i >= 0; i--) {
722             if (i in self && sought === self[i]) {
723                 return i;
724             }
725         }
726         return -1;
727     }
728 }, hasFirefox2LastIndexOfBug);
731 // Object
732 // ======
735 // ES5 15.2.3.14
736 // http://es5.github.com/#x15.2.3.14
738 // http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation
739 var hasDontEnumBug = !({'toString': null}).propertyIsEnumerable('toString'),
740     hasProtoEnumBug = (function () {}).propertyIsEnumerable('prototype'),
741     dontEnums = [
742         "toString",
743         "toLocaleString",
744         "valueOf",
745         "hasOwnProperty",
746         "isPrototypeOf",
747         "propertyIsEnumerable",
748         "constructor"
749     ],
750     dontEnumsLength = dontEnums.length;
752 defineProperties(Object, {
753     keys: function keys(object) {
754         var isFn = isFunction(object),
755             isArgs = isArguments(object),
756             isObject = object !== null && typeof object === 'object',
757             isStr = isObject && isString(object);
759         if (!isObject && !isFn && !isArgs) {
760             throw new TypeError("Object.keys called on a non-object");
761         }
763         var theKeys = [];
764         var skipProto = hasProtoEnumBug && isFn;
765         if (isStr || isArgs) {
766             for (var i = 0; i < object.length; ++i) {
767                 theKeys.push(String(i));
768             }
769         } else {
770             for (var name in object) {
771                 if (!(skipProto && name === 'prototype') && owns(object, name)) {
772                     theKeys.push(String(name));
773                 }
774             }
775         }
777         if (hasDontEnumBug) {
778             var ctor = object.constructor,
779                 skipConstructor = ctor && ctor.prototype === object;
780             for (var j = 0; j < dontEnumsLength; j++) {
781                 var dontEnum = dontEnums[j];
782                 if (!(skipConstructor && dontEnum === 'constructor') && owns(object, dontEnum)) {
783                     theKeys.push(dontEnum);
784                 }
785             }
786         }
787         return theKeys;
788     }
791 var keysWorksWithArguments = Object.keys && (function () {
792     // Safari 5.0 bug
793     return Object.keys(arguments).length === 2;
794 }(1, 2));
795 var originalKeys = Object.keys;
796 defineProperties(Object, {
797     keys: function keys(object) {
798         if (isArguments(object)) {
799             return originalKeys(ArrayPrototype.slice.call(object));
800         } else {
801             return originalKeys(object);
802         }
803     }
804 }, !keysWorksWithArguments);
807 // Date
808 // ====
811 // ES5 15.9.5.43
812 // http://es5.github.com/#x15.9.5.43
813 // This function returns a String value represent the instance in time
814 // represented by this Date object. The format of the String is the Date Time
815 // string format defined in 15.9.1.15. All fields are present in the String.
816 // The time zone is always UTC, denoted by the suffix Z. If the time value of
817 // this object is not a finite Number a RangeError exception is thrown.
818 var negativeDate = -62198755200000;
819 var negativeYearString = "-000001";
820 var hasNegativeDateBug = Date.prototype.toISOString && new Date(negativeDate).toISOString().indexOf(negativeYearString) === -1;
822 defineProperties(Date.prototype, {
823     toISOString: function toISOString() {
824         var result, length, value, year, month;
825         if (!isFinite(this)) {
826             throw new RangeError("Date.prototype.toISOString called on non-finite value.");
827         }
829         year = this.getUTCFullYear();
831         month = this.getUTCMonth();
832         // see https://github.com/es-shims/es5-shim/issues/111
833         year += Math.floor(month / 12);
834         month = (month % 12 + 12) % 12;
836         // the date time string format is specified in 15.9.1.15.
837         result = [month + 1, this.getUTCDate(), this.getUTCHours(), this.getUTCMinutes(), this.getUTCSeconds()];
838         year = (
839             (year < 0 ? "-" : (year > 9999 ? "+" : "")) +
840             ("00000" + Math.abs(year)).slice(0 <= year && year <= 9999 ? -4 : -6)
841         );
843         length = result.length;
844         while (length--) {
845             value = result[length];
846             // pad months, days, hours, minutes, and seconds to have two
847             // digits.
848             if (value < 10) {
849                 result[length] = "0" + value;
850             }
851         }
852         // pad milliseconds to have three digits.
853         return (
854             year + "-" + result.slice(0, 2).join("-") +
855             "T" + result.slice(2).join(":") + "." +
856             ("000" + this.getUTCMilliseconds()).slice(-3) + "Z"
857         );
858     }
859 }, hasNegativeDateBug);
862 // ES5 15.9.5.44
863 // http://es5.github.com/#x15.9.5.44
864 // This function provides a String representation of a Date object for use by
865 // JSON.stringify (15.12.3).
866 var dateToJSONIsSupported = false;
867 try {
868     dateToJSONIsSupported = (
869         Date.prototype.toJSON &&
870         new Date(NaN).toJSON() === null &&
871         new Date(negativeDate).toJSON().indexOf(negativeYearString) !== -1 &&
872         Date.prototype.toJSON.call({ // generic
873             toISOString: function () {
874                 return true;
875             }
876         })
877     );
878 } catch (e) {
880 if (!dateToJSONIsSupported) {
881     Date.prototype.toJSON = function toJSON(key) {
882         // When the toJSON method is called with argument key, the following
883         // steps are taken:
885         // 1.  Let O be the result of calling ToObject, giving it the this
886         // value as its argument.
887         // 2. Let tv be toPrimitive(O, hint Number).
888         var o = Object(this),
889             tv = toPrimitive(o),
890             toISO;
891         // 3. If tv is a Number and is not finite, return null.
892         if (typeof tv === "number" && !isFinite(tv)) {
893             return null;
894         }
895         // 4. Let toISO be the result of calling the [[Get]] internal method of
896         // O with argument "toISOString".
897         toISO = o.toISOString;
898         // 5. If IsCallable(toISO) is false, throw a TypeError exception.
899         if (typeof toISO !== "function") {
900             throw new TypeError("toISOString property is not callable");
901         }
902         // 6. Return the result of calling the [[Call]] internal method of
903         //  toISO with O as the this value and an empty argument list.
904         return toISO.call(o);
906         // NOTE 1 The argument is ignored.
908         // NOTE 2 The toJSON function is intentionally generic; it does not
909         // require that its this value be a Date object. Therefore, it can be
910         // transferred to other kinds of objects for use as a method. However,
911         // it does require that any such object have a toISOString method. An
912         // object is free to use the argument key to filter its
913         // stringification.
914     };
917 // ES5 15.9.4.2
918 // http://es5.github.com/#x15.9.4.2
919 // based on work shared by Daniel Friesen (dantman)
920 // http://gist.github.com/303249
921 var supportsExtendedYears = Date.parse('+033658-09-27T01:46:40.000Z') === 1e15;
922 var acceptsInvalidDates = !isNaN(Date.parse('2012-04-04T24:00:00.500Z')) || !isNaN(Date.parse('2012-11-31T23:59:59.000Z'));
923 var doesNotParseY2KNewYear = isNaN(Date.parse("2000-01-01T00:00:00.000Z"));
924 if (!Date.parse || doesNotParseY2KNewYear || acceptsInvalidDates || !supportsExtendedYears) {
925     // XXX global assignment won't work in embeddings that use
926     // an alternate object for the context.
927     Date = (function (NativeDate) {
929         // Date.length === 7
930         function Date(Y, M, D, h, m, s, ms) {
931             var length = arguments.length;
932             if (this instanceof NativeDate) {
933                 var date = length === 1 && String(Y) === Y ? // isString(Y)
934                     // We explicitly pass it through parse:
935                     new NativeDate(Date.parse(Y)) :
936                     // We have to manually make calls depending on argument
937                     // length here
938                     length >= 7 ? new NativeDate(Y, M, D, h, m, s, ms) :
939                     length >= 6 ? new NativeDate(Y, M, D, h, m, s) :
940                     length >= 5 ? new NativeDate(Y, M, D, h, m) :
941                     length >= 4 ? new NativeDate(Y, M, D, h) :
942                     length >= 3 ? new NativeDate(Y, M, D) :
943                     length >= 2 ? new NativeDate(Y, M) :
944                     length >= 1 ? new NativeDate(Y) :
945                                   new NativeDate();
946                 // Prevent mixups with unfixed Date object
947                 date.constructor = Date;
948                 return date;
949             }
950             return NativeDate.apply(this, arguments);
951         }
953         // 15.9.1.15 Date Time String Format.
954         var isoDateExpression = new RegExp("^" +
955             "(\\d{4}|[\+\-]\\d{6})" + // four-digit year capture or sign +
956                                       // 6-digit extended year
957             "(?:-(\\d{2})" + // optional month capture
958             "(?:-(\\d{2})" + // optional day capture
959             "(?:" + // capture hours:minutes:seconds.milliseconds
960                 "T(\\d{2})" + // hours capture
961                 ":(\\d{2})" + // minutes capture
962                 "(?:" + // optional :seconds.milliseconds
963                     ":(\\d{2})" + // seconds capture
964                     "(?:(\\.\\d{1,}))?" + // milliseconds capture
965                 ")?" +
966             "(" + // capture UTC offset component
967                 "Z|" + // UTC capture
968                 "(?:" + // offset specifier +/-hours:minutes
969                     "([-+])" + // sign capture
970                     "(\\d{2})" + // hours offset capture
971                     ":(\\d{2})" + // minutes offset capture
972                 ")" +
973             ")?)?)?)?" +
974         "$");
976         var months = [
977             0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
978         ];
980         function dayFromMonth(year, month) {
981             var t = month > 1 ? 1 : 0;
982             return (
983                 months[month] +
984                 Math.floor((year - 1969 + t) / 4) -
985                 Math.floor((year - 1901 + t) / 100) +
986                 Math.floor((year - 1601 + t) / 400) +
987                 365 * (year - 1970)
988             );
989         }
991         function toUTC(t) {
992             return Number(new NativeDate(1970, 0, 1, 0, 0, 0, t));
993         }
995         // Copy any custom methods a 3rd party library may have added
996         for (var key in NativeDate) {
997             Date[key] = NativeDate[key];
998         }
1000         // Copy "native" methods explicitly; they may be non-enumerable
1001         Date.now = NativeDate.now;
1002         Date.UTC = NativeDate.UTC;
1003         Date.prototype = NativeDate.prototype;
1004         Date.prototype.constructor = Date;
1006         // Upgrade Date.parse to handle simplified ISO 8601 strings
1007         Date.parse = function parse(string) {
1008             var match = isoDateExpression.exec(string);
1009             if (match) {
1010                 // parse months, days, hours, minutes, seconds, and milliseconds
1011                 // provide default values if necessary
1012                 // parse the UTC offset component
1013                 var year = Number(match[1]),
1014                     month = Number(match[2] || 1) - 1,
1015                     day = Number(match[3] || 1) - 1,
1016                     hour = Number(match[4] || 0),
1017                     minute = Number(match[5] || 0),
1018                     second = Number(match[6] || 0),
1019                     millisecond = Math.floor(Number(match[7] || 0) * 1000),
1020                     // When time zone is missed, local offset should be used
1021                     // (ES 5.1 bug)
1022                     // see https://bugs.ecmascript.org/show_bug.cgi?id=112
1023                     isLocalTime = Boolean(match[4] && !match[8]),
1024                     signOffset = match[9] === "-" ? 1 : -1,
1025                     hourOffset = Number(match[10] || 0),
1026                     minuteOffset = Number(match[11] || 0),
1027                     result;
1028                 if (
1029                     hour < (
1030                         minute > 0 || second > 0 || millisecond > 0 ?
1031                         24 : 25
1032                     ) &&
1033                     minute < 60 && second < 60 && millisecond < 1000 &&
1034                     month > -1 && month < 12 && hourOffset < 24 &&
1035                     minuteOffset < 60 && // detect invalid offsets
1036                     day > -1 &&
1037                     day < (
1038                         dayFromMonth(year, month + 1) -
1039                         dayFromMonth(year, month)
1040                     )
1041                 ) {
1042                     result = (
1043                         (dayFromMonth(year, month) + day) * 24 +
1044                         hour +
1045                         hourOffset * signOffset
1046                     ) * 60;
1047                     result = (
1048                         (result + minute + minuteOffset * signOffset) * 60 +
1049                         second
1050                     ) * 1000 + millisecond;
1051                     if (isLocalTime) {
1052                         result = toUTC(result);
1053                     }
1054                     if (-8.64e15 <= result && result <= 8.64e15) {
1055                         return result;
1056                     }
1057                 }
1058                 return NaN;
1059             }
1060             return NativeDate.parse.apply(this, arguments);
1061         };
1063         return Date;
1064     })(Date);
1067 // ES5 15.9.4.4
1068 // http://es5.github.com/#x15.9.4.4
1069 if (!Date.now) {
1070     Date.now = function now() {
1071         return new Date().getTime();
1072     };
1077 // Number
1078 // ======
1081 // ES5.1 15.7.4.5
1082 // http://es5.github.com/#x15.7.4.5
1083 var hasToFixedBugs = NumberPrototype.toFixed && (
1084   (0.00008).toFixed(3) !== '0.000'
1085   || (0.9).toFixed(0) === '0'
1086   || (1.255).toFixed(2) !== '1.25'
1087   || (1000000000000000128).toFixed(0) !== "1000000000000000128"
1090 var toFixedHelpers = {
1091   base: 1e7,
1092   size: 6,
1093   data: [0, 0, 0, 0, 0, 0],
1094   multiply: function multiply(n, c) {
1095       var i = -1;
1096       while (++i < toFixedHelpers.size) {
1097           c += n * toFixedHelpers.data[i];
1098           toFixedHelpers.data[i] = c % toFixedHelpers.base;
1099           c = Math.floor(c / toFixedHelpers.base);
1100       }
1101   },
1102   divide: function divide(n) {
1103       var i = toFixedHelpers.size, c = 0;
1104       while (--i >= 0) {
1105           c += toFixedHelpers.data[i];
1106           toFixedHelpers.data[i] = Math.floor(c / n);
1107           c = (c % n) * toFixedHelpers.base;
1108       }
1109   },
1110   numToString: function numToString() {
1111       var i = toFixedHelpers.size;
1112       var s = '';
1113       while (--i >= 0) {
1114           if (s !== '' || i === 0 || toFixedHelpers.data[i] !== 0) {
1115               var t = String(toFixedHelpers.data[i]);
1116               if (s === '') {
1117                   s = t;
1118               } else {
1119                   s += '0000000'.slice(0, 7 - t.length) + t;
1120               }
1121           }
1122       }
1123       return s;
1124   },
1125   pow: function pow(x, n, acc) {
1126       return (n === 0 ? acc : (n % 2 === 1 ? pow(x, n - 1, acc * x) : pow(x * x, n / 2, acc)));
1127   },
1128   log: function log(x) {
1129       var n = 0;
1130       while (x >= 4096) {
1131           n += 12;
1132           x /= 4096;
1133       }
1134       while (x >= 2) {
1135           n += 1;
1136           x /= 2;
1137       }
1138       return n;
1139   }
1142 defineProperties(NumberPrototype, {
1143     toFixed: function toFixed(fractionDigits) {
1144         var f, x, s, m, e, z, j, k;
1146         // Test for NaN and round fractionDigits down
1147         f = Number(fractionDigits);
1148         f = f !== f ? 0 : Math.floor(f);
1150         if (f < 0 || f > 20) {
1151             throw new RangeError("Number.toFixed called with invalid number of decimals");
1152         }
1154         x = Number(this);
1156         // Test for NaN
1157         if (x !== x) {
1158             return "NaN";
1159         }
1161         // If it is too big or small, return the string value of the number
1162         if (x <= -1e21 || x >= 1e21) {
1163             return String(x);
1164         }
1166         s = "";
1168         if (x < 0) {
1169             s = "-";
1170             x = -x;
1171         }
1173         m = "0";
1175         if (x > 1e-21) {
1176             // 1e-21 < x < 1e21
1177             // -70 < log2(x) < 70
1178             e = toFixedHelpers.log(x * toFixedHelpers.pow(2, 69, 1)) - 69;
1179             z = (e < 0 ? x * toFixedHelpers.pow(2, -e, 1) : x / toFixedHelpers.pow(2, e, 1));
1180             z *= 0x10000000000000; // Math.pow(2, 52);
1181             e = 52 - e;
1183             // -18 < e < 122
1184             // x = z / 2 ^ e
1185             if (e > 0) {
1186                 toFixedHelpers.multiply(0, z);
1187                 j = f;
1189                 while (j >= 7) {
1190                     toFixedHelpers.multiply(1e7, 0);
1191                     j -= 7;
1192                 }
1194                 toFixedHelpers.multiply(toFixedHelpers.pow(10, j, 1), 0);
1195                 j = e - 1;
1197                 while (j >= 23) {
1198                     toFixedHelpers.divide(1 << 23);
1199                     j -= 23;
1200                 }
1202                 toFixedHelpers.divide(1 << j);
1203                 toFixedHelpers.multiply(1, 1);
1204                 toFixedHelpers.divide(2);
1205                 m = toFixedHelpers.numToString();
1206             } else {
1207                 toFixedHelpers.multiply(0, z);
1208                 toFixedHelpers.multiply(1 << (-e), 0);
1209                 m = toFixedHelpers.numToString() + '0.00000000000000000000'.slice(2, 2 + f);
1210             }
1211         }
1213         if (f > 0) {
1214             k = m.length;
1216             if (k <= f) {
1217                 m = s + '0.0000000000000000000'.slice(0, f - k + 2) + m;
1218             } else {
1219                 m = s + m.slice(0, k - f) + '.' + m.slice(k - f);
1220             }
1221         } else {
1222             m = s + m;
1223         }
1225         return m;
1226     }
1227 }, hasToFixedBugs);
1231 // String
1232 // ======
1235 // ES5 15.5.4.14
1236 // http://es5.github.com/#x15.5.4.14
1238 // [bugfix, IE lt 9, firefox 4, Konqueror, Opera, obscure browsers]
1239 // Many browsers do not split properly with regular expressions or they
1240 // do not perform the split correctly under obscure conditions.
1241 // See http://blog.stevenlevithan.com/archives/cross-browser-split
1242 // I've tested in many browsers and this seems to cover the deviant ones:
1243 //    'ab'.split(/(?:ab)*/) should be ["", ""], not [""]
1244 //    '.'.split(/(.?)(.?)/) should be ["", ".", "", ""], not ["", ""]
1245 //    'tesst'.split(/(s)*/) should be ["t", undefined, "e", "s", "t"], not
1246 //       [undefined, "t", undefined, "e", ...]
1247 //    ''.split(/.?/) should be [], not [""]
1248 //    '.'.split(/()()/) should be ["."], not ["", "", "."]
1250 var string_split = StringPrototype.split;
1251 if (
1252     'ab'.split(/(?:ab)*/).length !== 2 ||
1253     '.'.split(/(.?)(.?)/).length !== 4 ||
1254     'tesst'.split(/(s)*/)[1] === "t" ||
1255     'test'.split(/(?:)/, -1).length !== 4 ||
1256     ''.split(/.?/).length ||
1257     '.'.split(/()()/).length > 1
1258 ) {
1259     (function () {
1260         var compliantExecNpcg = /()??/.exec("")[1] === void 0; // NPCG: nonparticipating capturing group
1262         StringPrototype.split = function (separator, limit) {
1263             var string = this;
1264             if (separator === void 0 && limit === 0) {
1265                 return [];
1266             }
1268             // If `separator` is not a regex, use native split
1269             if (_toString.call(separator) !== "[object RegExp]") {
1270                 return string_split.call(this, separator, limit);
1271             }
1273             var output = [],
1274                 flags = (separator.ignoreCase ? "i" : "") +
1275                         (separator.multiline  ? "m" : "") +
1276                         (separator.extended   ? "x" : "") + // Proposed for ES6
1277                         (separator.sticky     ? "y" : ""), // Firefox 3+
1278                 lastLastIndex = 0,
1279                 // Make `global` and avoid `lastIndex` issues by working with a copy
1280                 separator2, match, lastIndex, lastLength;
1281             separator = new RegExp(separator.source, flags + "g");
1282             string += ""; // Type-convert
1283             if (!compliantExecNpcg) {
1284                 // Doesn't need flags gy, but they don't hurt
1285                 separator2 = new RegExp("^" + separator.source + "$(?!\\s)", flags);
1286             }
1287             /* Values for `limit`, per the spec:
1288              * If undefined: 4294967295 // Math.pow(2, 32) - 1
1289              * If 0, Infinity, or NaN: 0
1290              * If positive number: limit = Math.floor(limit); if (limit > 4294967295) limit -= 4294967296;
1291              * If negative number: 4294967296 - Math.floor(Math.abs(limit))
1292              * If other: Type-convert, then use the above rules
1293              */
1294             limit = limit === void 0 ?
1295                 -1 >>> 0 : // Math.pow(2, 32) - 1
1296                 ToUint32(limit);
1297             while (match = separator.exec(string)) {
1298                 // `separator.lastIndex` is not reliable cross-browser
1299                 lastIndex = match.index + match[0].length;
1300                 if (lastIndex > lastLastIndex) {
1301                     output.push(string.slice(lastLastIndex, match.index));
1302                     // Fix browsers whose `exec` methods don't consistently return `undefined` for
1303                     // nonparticipating capturing groups
1304                     if (!compliantExecNpcg && match.length > 1) {
1305                         match[0].replace(separator2, function () {
1306                             for (var i = 1; i < arguments.length - 2; i++) {
1307                                 if (arguments[i] === void 0) {
1308                                     match[i] = void 0;
1309                                 }
1310                             }
1311                         });
1312                     }
1313                     if (match.length > 1 && match.index < string.length) {
1314                         ArrayPrototype.push.apply(output, match.slice(1));
1315                     }
1316                     lastLength = match[0].length;
1317                     lastLastIndex = lastIndex;
1318                     if (output.length >= limit) {
1319                         break;
1320                     }
1321                 }
1322                 if (separator.lastIndex === match.index) {
1323                     separator.lastIndex++; // Avoid an infinite loop
1324                 }
1325             }
1326             if (lastLastIndex === string.length) {
1327                 if (lastLength || !separator.test("")) {
1328                     output.push("");
1329                 }
1330             } else {
1331                 output.push(string.slice(lastLastIndex));
1332             }
1333             return output.length > limit ? output.slice(0, limit) : output;
1334         };
1335     }());
1337 // [bugfix, chrome]
1338 // If separator is undefined, then the result array contains just one String,
1339 // which is the this value (converted to a String). If limit is not undefined,
1340 // then the output array is truncated so that it contains no more than limit
1341 // elements.
1342 // "0".split(undefined, 0) -> []
1343 } else if ("0".split(void 0, 0).length) {
1344     StringPrototype.split = function split(separator, limit) {
1345         if (separator === void 0 && limit === 0) { return []; }
1346         return string_split.call(this, separator, limit);
1347     };
1350 var str_replace = StringPrototype.replace;
1351 var replaceReportsGroupsCorrectly = (function () {
1352     var groups = [];
1353     'x'.replace(/x(.)?/g, function (match, group) {
1354         groups.push(group);
1355     });
1356     return groups.length === 1 && typeof groups[0] === 'undefined';
1357 }());
1359 if (!replaceReportsGroupsCorrectly) {
1360     StringPrototype.replace = function replace(searchValue, replaceValue) {
1361         var isFn = isFunction(replaceValue);
1362         var hasCapturingGroups = isRegex(searchValue) && (/\)[*?]/).test(searchValue.source);
1363         if (!isFn || !hasCapturingGroups) {
1364             return str_replace.call(this, searchValue, replaceValue);
1365         } else {
1366             var wrappedReplaceValue = function (match) {
1367                 var length = arguments.length;
1368                 var originalLastIndex = searchValue.lastIndex;
1369                 searchValue.lastIndex = 0;
1370                 var args = searchValue.exec(match);
1371                 searchValue.lastIndex = originalLastIndex;
1372                 args.push(arguments[length - 2], arguments[length - 1]);
1373                 return replaceValue.apply(this, args);
1374             };
1375             return str_replace.call(this, searchValue, wrappedReplaceValue);
1376         }
1377     };
1380 // ECMA-262, 3rd B.2.3
1381 // Not an ECMAScript standard, although ECMAScript 3rd Edition has a
1382 // non-normative section suggesting uniform semantics and it should be
1383 // normalized across all browsers
1384 // [bugfix, IE lt 9] IE < 9 substr() with negative value not working in IE
1385 var string_substr = StringPrototype.substr;
1386 var hasNegativeSubstrBug = "".substr && "0b".substr(-1) !== "b";
1387 defineProperties(StringPrototype, {
1388     substr: function substr(start, length) {
1389         return string_substr.call(
1390             this,
1391             start < 0 ? ((start = this.length + start) < 0 ? 0 : start) : start,
1392             length
1393         );
1394     }
1395 }, hasNegativeSubstrBug);
1397 // ES5 15.5.4.20
1398 // whitespace from: http://es5.github.io/#x15.5.4.20
1399 var ws = "\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003" +
1400     "\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028" +
1401     "\u2029\uFEFF";
1402 var zeroWidth = '\u200b';
1403 var wsRegexChars = "[" + ws + "]";
1404 var trimBeginRegexp = new RegExp("^" + wsRegexChars + wsRegexChars + "*");
1405 var trimEndRegexp = new RegExp(wsRegexChars + wsRegexChars + "*$");
1406 var hasTrimWhitespaceBug = StringPrototype.trim && (ws.trim() || !zeroWidth.trim());
1407 defineProperties(StringPrototype, {
1408     // http://blog.stevenlevithan.com/archives/faster-trim-javascript
1409     // http://perfectionkills.com/whitespace-deviations/
1410     trim: function trim() {
1411         if (this === void 0 || this === null) {
1412             throw new TypeError("can't convert " + this + " to object");
1413         }
1414         return String(this).replace(trimBeginRegexp, "").replace(trimEndRegexp, "");
1415     }
1416 }, hasTrimWhitespaceBug);
1418 // ES-5 15.1.2.2
1419 if (parseInt(ws + '08') !== 8 || parseInt(ws + '0x16') !== 22) {
1420     parseInt = (function (origParseInt) {
1421         var hexRegex = /^0[xX]/;
1422         return function parseIntES5(str, radix) {
1423             str = String(str).trim();
1424             if (!Number(radix)) {
1425                 radix = hexRegex.test(str) ? 16 : 10;
1426             }
1427             return origParseInt(str, radix);
1428         };
1429     }(parseInt));
1432 }));