Merge "Add link on Special:Upload to edit MediaWiki:Licenses"
[lhc/web/wiklou.git] / resources / lib / es5-shim / es5-shim.js
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 */
6
7 // vim: ts=4 sts=4 sw=4 expandtab
8
9 //Add semicolon to prevent IIFE from being passed as argument to concated code.
10 ;
11
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 () {
28
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 */
37
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;
50
51 // Having a toString local variable name breaks in Opera so use _toString.
52 var _toString = ObjectPrototype.toString;
53
54 var isFunction = function (val) {
55 return ObjectPrototype.toString.call(val) === '[object Function]';
56 };
57 var isRegex = function (val) {
58 return ObjectPrototype.toString.call(val) === '[object RegExp]';
59 };
60 var isArray = function isArray(obj) {
61 return _toString.call(obj) === "[object Array]";
62 };
63 var isString = function isString(obj) {
64 return _toString.call(obj) === "[object String]";
65 };
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;
78 };
79
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 }());
88
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 };
107 }
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 }
114 };
115
116 //
117 // Util
118 // ======
119 //
120
121 // ES5 9.4
122 // http://es5.github.com/#x9.4
123 // http://jsperf.com/to-integer
124
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;
133 }
134
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 );
144 }
145
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();
166 }
167
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);
175 };
176
177 var ToUint32 = function ToUint32(x) {
178 return x >>> 0;
179 };
180
181 //
182 // Function
183 // ========
184 //
185
186 // ES-5 15.3.4.5
187 // http://es5.github.com/#x15.3.4.5
188
189 function Empty() {}
190
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 () {
213
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.
230
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;
239
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.
258
259 // equiv: target.call(this, ...boundArgs, ...args)
260 return target.apply(
261 that,
262 args.concat(_Array_slice_.call(arguments))
263 );
264
265 }
266
267 };
268
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.
274
275 var boundLength = Math.max(0, target.length - args.length);
276
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 }
283
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);
291
292 if (target.prototype) {
293 Empty.prototype = target.prototype;
294 bound.prototype = new Empty();
295 // Clean up dangling references.
296 Empty.prototype = null;
297 }
298
299 // TODO
300 // 18. Set the [[Extensible]] internal property of F to true.
301
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.
312
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.
318
319 // 22. Return F.
320 return bound;
321 }
322 });
323
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);
327
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__);
339 }
340
341 //
342 // Array
343 // =====
344 //
345
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);
363
364 var spliceWorksWithEmptyObject = (function () {
365 var obj = {};
366 ArrayPrototype.splice.call(obj, 0, 0, 1);
367 return obj.length === 1;
368 }());
369 defineProperties(ArrayPrototype, {
370 splice: function splice(start, deleteCount) {
371 if (arguments.length === 0) { return []; }
372 var args = arguments;
373 this.length = Math.max(toInteger(this.length), 0);
374 if (arguments.length > 0 && typeof deleteCount !== 'number') {
375 args = _Array_slice_.call(arguments);
376 if (args.length < 2) {
377 args.push(this.length - start);
378 } else {
379 args[1] = toInteger(deleteCount);
380 }
381 }
382 return array_splice.apply(this, args);
383 }
384 }, !spliceWorksWithEmptyObject);
385
386 // ES5 15.4.4.12
387 // http://es5.github.com/#x15.4.4.13
388 // Return len+argCount.
389 // [bugfix, ielt8]
390 // IE < 8 bug: [].unshift(0) === undefined but should be "1"
391 var hasUnshiftReturnValueBug = [].unshift(0) !== 1;
392 defineProperties(ArrayPrototype, {
393 unshift: function () {
394 array_unshift.apply(this, arguments);
395 return this.length;
396 }
397 }, hasUnshiftReturnValueBug);
398
399 // ES5 15.4.3.2
400 // http://es5.github.com/#x15.4.3.2
401 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/isArray
402 defineProperties(Array, { isArray: isArray });
403
404 // The IsCallable() check in the Array functions
405 // has been replaced with a strict check on the
406 // internal class of the object to trap cases where
407 // the provided function was actually a regular
408 // expression literal, which in V8 and
409 // JavaScriptCore is a typeof "function". Only in
410 // V8 are regular expression literals permitted as
411 // reduce parameters, so it is desirable in the
412 // general case for the shim to match the more
413 // strict and common behavior of rejecting regular
414 // expressions.
415
416 // ES5 15.4.4.18
417 // http://es5.github.com/#x15.4.4.18
418 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/forEach
419
420 // Check failure of by-index access of string characters (IE < 9)
421 // and failure of `0 in boxedString` (Rhino)
422 var boxedString = Object("a");
423 var splitString = boxedString[0] !== "a" || !(0 in boxedString);
424
425 var properlyBoxesContext = function properlyBoxed(method) {
426 // Check node 0.6.21 bug where third parameter is not boxed
427 var properlyBoxesNonStrict = true;
428 var properlyBoxesStrict = true;
429 if (method) {
430 method.call('foo', function (_, __, context) {
431 if (typeof context !== 'object') { properlyBoxesNonStrict = false; }
432 });
433
434 method.call([1], function () {
435 'use strict';
436 properlyBoxesStrict = typeof this === 'string';
437 }, 'x');
438 }
439 return !!method && properlyBoxesNonStrict && properlyBoxesStrict;
440 };
441
442 defineProperties(ArrayPrototype, {
443 forEach: function forEach(fun /*, thisp*/) {
444 var object = toObject(this),
445 self = splitString && isString(this) ? this.split('') : object,
446 thisp = arguments[1],
447 i = -1,
448 length = self.length >>> 0;
449
450 // If no callback function or if callback is not a callable function
451 if (!isFunction(fun)) {
452 throw new TypeError(); // TODO message
453 }
454
455 while (++i < length) {
456 if (i in self) {
457 // Invoke the callback function with call, passing arguments:
458 // context, property value, property key, thisArg object
459 // context
460 fun.call(thisp, self[i], i, object);
461 }
462 }
463 }
464 }, !properlyBoxesContext(ArrayPrototype.forEach));
465
466 // ES5 15.4.4.19
467 // http://es5.github.com/#x15.4.4.19
468 // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/map
469 defineProperties(ArrayPrototype, {
470 map: function map(fun /*, thisp*/) {
471 var object = toObject(this),
472 self = splitString && isString(this) ? this.split('') : object,
473 length = self.length >>> 0,
474 result = Array(length),
475 thisp = arguments[1];
476
477 // If no callback function or if callback is not a callable function
478 if (!isFunction(fun)) {
479 throw new TypeError(fun + " is not a function");
480 }
481
482 for (var i = 0; i < length; i++) {
483 if (i in self) {
484 result[i] = fun.call(thisp, self[i], i, object);
485 }
486 }
487 return result;
488 }
489 }, !properlyBoxesContext(ArrayPrototype.map));
490
491 // ES5 15.4.4.20
492 // http://es5.github.com/#x15.4.4.20
493 // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/filter
494 defineProperties(ArrayPrototype, {
495 filter: function filter(fun /*, thisp */) {
496 var object = toObject(this),
497 self = splitString && isString(this) ? this.split('') : object,
498 length = self.length >>> 0,
499 result = [],
500 value,
501 thisp = arguments[1];
502
503 // If no callback function or if callback is not a callable function
504 if (!isFunction(fun)) {
505 throw new TypeError(fun + " is not a function");
506 }
507
508 for (var i = 0; i < length; i++) {
509 if (i in self) {
510 value = self[i];
511 if (fun.call(thisp, value, i, object)) {
512 result.push(value);
513 }
514 }
515 }
516 return result;
517 }
518 }, !properlyBoxesContext(ArrayPrototype.filter));
519
520 // ES5 15.4.4.16
521 // http://es5.github.com/#x15.4.4.16
522 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/every
523 defineProperties(ArrayPrototype, {
524 every: function every(fun /*, thisp */) {
525 var object = toObject(this),
526 self = splitString && isString(this) ? this.split('') : object,
527 length = self.length >>> 0,
528 thisp = arguments[1];
529
530 // If no callback function or if callback is not a callable function
531 if (!isFunction(fun)) {
532 throw new TypeError(fun + " is not a function");
533 }
534
535 for (var i = 0; i < length; i++) {
536 if (i in self && !fun.call(thisp, self[i], i, object)) {
537 return false;
538 }
539 }
540 return true;
541 }
542 }, !properlyBoxesContext(ArrayPrototype.every));
543
544 // ES5 15.4.4.17
545 // http://es5.github.com/#x15.4.4.17
546 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/some
547 defineProperties(ArrayPrototype, {
548 some: function some(fun /*, thisp */) {
549 var object = toObject(this),
550 self = splitString && isString(this) ? this.split('') : object,
551 length = self.length >>> 0,
552 thisp = arguments[1];
553
554 // If no callback function or if callback is not a callable function
555 if (!isFunction(fun)) {
556 throw new TypeError(fun + " is not a function");
557 }
558
559 for (var i = 0; i < length; i++) {
560 if (i in self && fun.call(thisp, self[i], i, object)) {
561 return true;
562 }
563 }
564 return false;
565 }
566 }, !properlyBoxesContext(ArrayPrototype.some));
567
568 // ES5 15.4.4.21
569 // http://es5.github.com/#x15.4.4.21
570 // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduce
571 var reduceCoercesToObject = false;
572 if (ArrayPrototype.reduce) {
573 reduceCoercesToObject = typeof ArrayPrototype.reduce.call('es5', function (_, __, ___, list) { return list; }) === 'object';
574 }
575 defineProperties(ArrayPrototype, {
576 reduce: function reduce(fun /*, initial*/) {
577 var object = toObject(this),
578 self = splitString && isString(this) ? this.split('') : object,
579 length = self.length >>> 0;
580
581 // If no callback function or if callback is not a callable function
582 if (!isFunction(fun)) {
583 throw new TypeError(fun + " is not a function");
584 }
585
586 // no value to return if no initial value and an empty array
587 if (!length && arguments.length === 1) {
588 throw new TypeError("reduce of empty array with no initial value");
589 }
590
591 var i = 0;
592 var result;
593 if (arguments.length >= 2) {
594 result = arguments[1];
595 } else {
596 do {
597 if (i in self) {
598 result = self[i++];
599 break;
600 }
601
602 // if array contains no values, no initial value to return
603 if (++i >= length) {
604 throw new TypeError("reduce of empty array with no initial value");
605 }
606 } while (true);
607 }
608
609 for (; i < length; i++) {
610 if (i in self) {
611 result = fun.call(void 0, result, self[i], i, object);
612 }
613 }
614
615 return result;
616 }
617 }, !reduceCoercesToObject);
618
619 // ES5 15.4.4.22
620 // http://es5.github.com/#x15.4.4.22
621 // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduceRight
622 var reduceRightCoercesToObject = false;
623 if (ArrayPrototype.reduceRight) {
624 reduceRightCoercesToObject = typeof ArrayPrototype.reduceRight.call('es5', function (_, __, ___, list) { return list; }) === 'object';
625 }
626 defineProperties(ArrayPrototype, {
627 reduceRight: function reduceRight(fun /*, initial*/) {
628 var object = toObject(this),
629 self = splitString && isString(this) ? this.split('') : object,
630 length = self.length >>> 0;
631
632 // If no callback function or if callback is not a callable function
633 if (!isFunction(fun)) {
634 throw new TypeError(fun + " is not a function");
635 }
636
637 // no value to return if no initial value, empty array
638 if (!length && arguments.length === 1) {
639 throw new TypeError("reduceRight of empty array with no initial value");
640 }
641
642 var result, i = length - 1;
643 if (arguments.length >= 2) {
644 result = arguments[1];
645 } else {
646 do {
647 if (i in self) {
648 result = self[i--];
649 break;
650 }
651
652 // if array contains no values, no initial value to return
653 if (--i < 0) {
654 throw new TypeError("reduceRight of empty array with no initial value");
655 }
656 } while (true);
657 }
658
659 if (i < 0) {
660 return result;
661 }
662
663 do {
664 if (i in self) {
665 result = fun.call(void 0, result, self[i], i, object);
666 }
667 } while (i--);
668
669 return result;
670 }
671 }, !reduceRightCoercesToObject);
672
673 // ES5 15.4.4.14
674 // http://es5.github.com/#x15.4.4.14
675 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf
676 var hasFirefox2IndexOfBug = Array.prototype.indexOf && [0, 1].indexOf(1, 2) !== -1;
677 defineProperties(ArrayPrototype, {
678 indexOf: function indexOf(sought /*, fromIndex */ ) {
679 var self = splitString && isString(this) ? this.split('') : toObject(this),
680 length = self.length >>> 0;
681
682 if (!length) {
683 return -1;
684 }
685
686 var i = 0;
687 if (arguments.length > 1) {
688 i = toInteger(arguments[1]);
689 }
690
691 // handle negative indices
692 i = i >= 0 ? i : Math.max(0, length + i);
693 for (; i < length; i++) {
694 if (i in self && self[i] === sought) {
695 return i;
696 }
697 }
698 return -1;
699 }
700 }, hasFirefox2IndexOfBug);
701
702 // ES5 15.4.4.15
703 // http://es5.github.com/#x15.4.4.15
704 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/lastIndexOf
705 var hasFirefox2LastIndexOfBug = Array.prototype.lastIndexOf && [0, 1].lastIndexOf(0, -3) !== -1;
706 defineProperties(ArrayPrototype, {
707 lastIndexOf: function lastIndexOf(sought /*, fromIndex */) {
708 var self = splitString && isString(this) ? this.split('') : toObject(this),
709 length = self.length >>> 0;
710
711 if (!length) {
712 return -1;
713 }
714 var i = length - 1;
715 if (arguments.length > 1) {
716 i = Math.min(i, toInteger(arguments[1]));
717 }
718 // handle negative indices
719 i = i >= 0 ? i : length - Math.abs(i);
720 for (; i >= 0; i--) {
721 if (i in self && sought === self[i]) {
722 return i;
723 }
724 }
725 return -1;
726 }
727 }, hasFirefox2LastIndexOfBug);
728
729 //
730 // Object
731 // ======
732 //
733
734 // ES5 15.2.3.14
735 // http://es5.github.com/#x15.2.3.14
736
737 // http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation
738 var hasDontEnumBug = !({'toString': null}).propertyIsEnumerable('toString'),
739 hasProtoEnumBug = (function () {}).propertyIsEnumerable('prototype'),
740 dontEnums = [
741 "toString",
742 "toLocaleString",
743 "valueOf",
744 "hasOwnProperty",
745 "isPrototypeOf",
746 "propertyIsEnumerable",
747 "constructor"
748 ],
749 dontEnumsLength = dontEnums.length;
750
751 defineProperties(Object, {
752 keys: function keys(object) {
753 var isFn = isFunction(object),
754 isArgs = isArguments(object),
755 isObject = object !== null && typeof object === 'object',
756 isStr = isObject && isString(object);
757
758 if (!isObject && !isFn && !isArgs) {
759 throw new TypeError("Object.keys called on a non-object");
760 }
761
762 var theKeys = [];
763 var skipProto = hasProtoEnumBug && isFn;
764 if (isStr || isArgs) {
765 for (var i = 0; i < object.length; ++i) {
766 theKeys.push(String(i));
767 }
768 } else {
769 for (var name in object) {
770 if (!(skipProto && name === 'prototype') && owns(object, name)) {
771 theKeys.push(String(name));
772 }
773 }
774 }
775
776 if (hasDontEnumBug) {
777 var ctor = object.constructor,
778 skipConstructor = ctor && ctor.prototype === object;
779 for (var j = 0; j < dontEnumsLength; j++) {
780 var dontEnum = dontEnums[j];
781 if (!(skipConstructor && dontEnum === 'constructor') && owns(object, dontEnum)) {
782 theKeys.push(dontEnum);
783 }
784 }
785 }
786 return theKeys;
787 }
788 });
789
790 var keysWorksWithArguments = Object.keys && (function () {
791 // Safari 5.0 bug
792 return Object.keys(arguments).length === 2;
793 }(1, 2));
794 var originalKeys = Object.keys;
795 defineProperties(Object, {
796 keys: function keys(object) {
797 if (isArguments(object)) {
798 return originalKeys(ArrayPrototype.slice.call(object));
799 } else {
800 return originalKeys(object);
801 }
802 }
803 }, !keysWorksWithArguments);
804
805 //
806 // Date
807 // ====
808 //
809
810 // ES5 15.9.5.43
811 // http://es5.github.com/#x15.9.5.43
812 // This function returns a String value represent the instance in time
813 // represented by this Date object. The format of the String is the Date Time
814 // string format defined in 15.9.1.15. All fields are present in the String.
815 // The time zone is always UTC, denoted by the suffix Z. If the time value of
816 // this object is not a finite Number a RangeError exception is thrown.
817 var negativeDate = -62198755200000;
818 var negativeYearString = "-000001";
819 var hasNegativeDateBug = Date.prototype.toISOString && new Date(negativeDate).toISOString().indexOf(negativeYearString) === -1;
820
821 defineProperties(Date.prototype, {
822 toISOString: function toISOString() {
823 var result, length, value, year, month;
824 if (!isFinite(this)) {
825 throw new RangeError("Date.prototype.toISOString called on non-finite value.");
826 }
827
828 year = this.getUTCFullYear();
829
830 month = this.getUTCMonth();
831 // see https://github.com/es-shims/es5-shim/issues/111
832 year += Math.floor(month / 12);
833 month = (month % 12 + 12) % 12;
834
835 // the date time string format is specified in 15.9.1.15.
836 result = [month + 1, this.getUTCDate(), this.getUTCHours(), this.getUTCMinutes(), this.getUTCSeconds()];
837 year = (
838 (year < 0 ? "-" : (year > 9999 ? "+" : "")) +
839 ("00000" + Math.abs(year)).slice(0 <= year && year <= 9999 ? -4 : -6)
840 );
841
842 length = result.length;
843 while (length--) {
844 value = result[length];
845 // pad months, days, hours, minutes, and seconds to have two
846 // digits.
847 if (value < 10) {
848 result[length] = "0" + value;
849 }
850 }
851 // pad milliseconds to have three digits.
852 return (
853 year + "-" + result.slice(0, 2).join("-") +
854 "T" + result.slice(2).join(":") + "." +
855 ("000" + this.getUTCMilliseconds()).slice(-3) + "Z"
856 );
857 }
858 }, hasNegativeDateBug);
859
860
861 // ES5 15.9.5.44
862 // http://es5.github.com/#x15.9.5.44
863 // This function provides a String representation of a Date object for use by
864 // JSON.stringify (15.12.3).
865 var dateToJSONIsSupported = false;
866 try {
867 dateToJSONIsSupported = (
868 Date.prototype.toJSON &&
869 new Date(NaN).toJSON() === null &&
870 new Date(negativeDate).toJSON().indexOf(negativeYearString) !== -1 &&
871 Date.prototype.toJSON.call({ // generic
872 toISOString: function () {
873 return true;
874 }
875 })
876 );
877 } catch (e) {
878 }
879 if (!dateToJSONIsSupported) {
880 Date.prototype.toJSON = function toJSON(key) {
881 // When the toJSON method is called with argument key, the following
882 // steps are taken:
883
884 // 1. Let O be the result of calling ToObject, giving it the this
885 // value as its argument.
886 // 2. Let tv be toPrimitive(O, hint Number).
887 var o = Object(this),
888 tv = toPrimitive(o),
889 toISO;
890 // 3. If tv is a Number and is not finite, return null.
891 if (typeof tv === "number" && !isFinite(tv)) {
892 return null;
893 }
894 // 4. Let toISO be the result of calling the [[Get]] internal method of
895 // O with argument "toISOString".
896 toISO = o.toISOString;
897 // 5. If IsCallable(toISO) is false, throw a TypeError exception.
898 if (typeof toISO !== "function") {
899 throw new TypeError("toISOString property is not callable");
900 }
901 // 6. Return the result of calling the [[Call]] internal method of
902 // toISO with O as the this value and an empty argument list.
903 return toISO.call(o);
904
905 // NOTE 1 The argument is ignored.
906
907 // NOTE 2 The toJSON function is intentionally generic; it does not
908 // require that its this value be a Date object. Therefore, it can be
909 // transferred to other kinds of objects for use as a method. However,
910 // it does require that any such object have a toISOString method. An
911 // object is free to use the argument key to filter its
912 // stringification.
913 };
914 }
915
916 // ES5 15.9.4.2
917 // http://es5.github.com/#x15.9.4.2
918 // based on work shared by Daniel Friesen (dantman)
919 // http://gist.github.com/303249
920 var supportsExtendedYears = Date.parse('+033658-09-27T01:46:40.000Z') === 1e15;
921 var acceptsInvalidDates = !isNaN(Date.parse('2012-04-04T24:00:00.500Z')) || !isNaN(Date.parse('2012-11-31T23:59:59.000Z'));
922 var doesNotParseY2KNewYear = isNaN(Date.parse("2000-01-01T00:00:00.000Z"));
923 if (!Date.parse || doesNotParseY2KNewYear || acceptsInvalidDates || !supportsExtendedYears) {
924 // XXX global assignment won't work in embeddings that use
925 // an alternate object for the context.
926 Date = (function (NativeDate) {
927
928 // Date.length === 7
929 function Date(Y, M, D, h, m, s, ms) {
930 var length = arguments.length;
931 if (this instanceof NativeDate) {
932 var date = length === 1 && String(Y) === Y ? // isString(Y)
933 // We explicitly pass it through parse:
934 new NativeDate(Date.parse(Y)) :
935 // We have to manually make calls depending on argument
936 // length here
937 length >= 7 ? new NativeDate(Y, M, D, h, m, s, ms) :
938 length >= 6 ? new NativeDate(Y, M, D, h, m, s) :
939 length >= 5 ? new NativeDate(Y, M, D, h, m) :
940 length >= 4 ? new NativeDate(Y, M, D, h) :
941 length >= 3 ? new NativeDate(Y, M, D) :
942 length >= 2 ? new NativeDate(Y, M) :
943 length >= 1 ? new NativeDate(Y) :
944 new NativeDate();
945 // Prevent mixups with unfixed Date object
946 date.constructor = Date;
947 return date;
948 }
949 return NativeDate.apply(this, arguments);
950 }
951
952 // 15.9.1.15 Date Time String Format.
953 var isoDateExpression = new RegExp("^" +
954 "(\\d{4}|[\+\-]\\d{6})" + // four-digit year capture or sign +
955 // 6-digit extended year
956 "(?:-(\\d{2})" + // optional month capture
957 "(?:-(\\d{2})" + // optional day capture
958 "(?:" + // capture hours:minutes:seconds.milliseconds
959 "T(\\d{2})" + // hours capture
960 ":(\\d{2})" + // minutes capture
961 "(?:" + // optional :seconds.milliseconds
962 ":(\\d{2})" + // seconds capture
963 "(?:(\\.\\d{1,}))?" + // milliseconds capture
964 ")?" +
965 "(" + // capture UTC offset component
966 "Z|" + // UTC capture
967 "(?:" + // offset specifier +/-hours:minutes
968 "([-+])" + // sign capture
969 "(\\d{2})" + // hours offset capture
970 ":(\\d{2})" + // minutes offset capture
971 ")" +
972 ")?)?)?)?" +
973 "$");
974
975 var months = [
976 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
977 ];
978
979 function dayFromMonth(year, month) {
980 var t = month > 1 ? 1 : 0;
981 return (
982 months[month] +
983 Math.floor((year - 1969 + t) / 4) -
984 Math.floor((year - 1901 + t) / 100) +
985 Math.floor((year - 1601 + t) / 400) +
986 365 * (year - 1970)
987 );
988 }
989
990 function toUTC(t) {
991 return Number(new NativeDate(1970, 0, 1, 0, 0, 0, t));
992 }
993
994 // Copy any custom methods a 3rd party library may have added
995 for (var key in NativeDate) {
996 Date[key] = NativeDate[key];
997 }
998
999 // Copy "native" methods explicitly; they may be non-enumerable
1000 Date.now = NativeDate.now;
1001 Date.UTC = NativeDate.UTC;
1002 Date.prototype = NativeDate.prototype;
1003 Date.prototype.constructor = Date;
1004
1005 // Upgrade Date.parse to handle simplified ISO 8601 strings
1006 Date.parse = function parse(string) {
1007 var match = isoDateExpression.exec(string);
1008 if (match) {
1009 // parse months, days, hours, minutes, seconds, and milliseconds
1010 // provide default values if necessary
1011 // parse the UTC offset component
1012 var year = Number(match[1]),
1013 month = Number(match[2] || 1) - 1,
1014 day = Number(match[3] || 1) - 1,
1015 hour = Number(match[4] || 0),
1016 minute = Number(match[5] || 0),
1017 second = Number(match[6] || 0),
1018 millisecond = Math.floor(Number(match[7] || 0) * 1000),
1019 // When time zone is missed, local offset should be used
1020 // (ES 5.1 bug)
1021 // see https://bugs.ecmascript.org/show_bug.cgi?id=112
1022 isLocalTime = Boolean(match[4] && !match[8]),
1023 signOffset = match[9] === "-" ? 1 : -1,
1024 hourOffset = Number(match[10] || 0),
1025 minuteOffset = Number(match[11] || 0),
1026 result;
1027 if (
1028 hour < (
1029 minute > 0 || second > 0 || millisecond > 0 ?
1030 24 : 25
1031 ) &&
1032 minute < 60 && second < 60 && millisecond < 1000 &&
1033 month > -1 && month < 12 && hourOffset < 24 &&
1034 minuteOffset < 60 && // detect invalid offsets
1035 day > -1 &&
1036 day < (
1037 dayFromMonth(year, month + 1) -
1038 dayFromMonth(year, month)
1039 )
1040 ) {
1041 result = (
1042 (dayFromMonth(year, month) + day) * 24 +
1043 hour +
1044 hourOffset * signOffset
1045 ) * 60;
1046 result = (
1047 (result + minute + minuteOffset * signOffset) * 60 +
1048 second
1049 ) * 1000 + millisecond;
1050 if (isLocalTime) {
1051 result = toUTC(result);
1052 }
1053 if (-8.64e15 <= result && result <= 8.64e15) {
1054 return result;
1055 }
1056 }
1057 return NaN;
1058 }
1059 return NativeDate.parse.apply(this, arguments);
1060 };
1061
1062 return Date;
1063 })(Date);
1064 }
1065
1066 // ES5 15.9.4.4
1067 // http://es5.github.com/#x15.9.4.4
1068 if (!Date.now) {
1069 Date.now = function now() {
1070 return new Date().getTime();
1071 };
1072 }
1073
1074
1075 //
1076 // Number
1077 // ======
1078 //
1079
1080 // ES5.1 15.7.4.5
1081 // http://es5.github.com/#x15.7.4.5
1082 var hasToFixedBugs = NumberPrototype.toFixed && (
1083 (0.00008).toFixed(3) !== '0.000'
1084 || (0.9).toFixed(0) !== '1'
1085 || (1.255).toFixed(2) !== '1.25'
1086 || (1000000000000000128).toFixed(0) !== "1000000000000000128"
1087 );
1088
1089 var toFixedHelpers = {
1090 base: 1e7,
1091 size: 6,
1092 data: [0, 0, 0, 0, 0, 0],
1093 multiply: function multiply(n, c) {
1094 var i = -1;
1095 while (++i < toFixedHelpers.size) {
1096 c += n * toFixedHelpers.data[i];
1097 toFixedHelpers.data[i] = c % toFixedHelpers.base;
1098 c = Math.floor(c / toFixedHelpers.base);
1099 }
1100 },
1101 divide: function divide(n) {
1102 var i = toFixedHelpers.size, c = 0;
1103 while (--i >= 0) {
1104 c += toFixedHelpers.data[i];
1105 toFixedHelpers.data[i] = Math.floor(c / n);
1106 c = (c % n) * toFixedHelpers.base;
1107 }
1108 },
1109 numToString: function numToString() {
1110 var i = toFixedHelpers.size;
1111 var s = '';
1112 while (--i >= 0) {
1113 if (s !== '' || i === 0 || toFixedHelpers.data[i] !== 0) {
1114 var t = String(toFixedHelpers.data[i]);
1115 if (s === '') {
1116 s = t;
1117 } else {
1118 s += '0000000'.slice(0, 7 - t.length) + t;
1119 }
1120 }
1121 }
1122 return s;
1123 },
1124 pow: function pow(x, n, acc) {
1125 return (n === 0 ? acc : (n % 2 === 1 ? pow(x, n - 1, acc * x) : pow(x * x, n / 2, acc)));
1126 },
1127 log: function log(x) {
1128 var n = 0;
1129 while (x >= 4096) {
1130 n += 12;
1131 x /= 4096;
1132 }
1133 while (x >= 2) {
1134 n += 1;
1135 x /= 2;
1136 }
1137 return n;
1138 }
1139 };
1140
1141 defineProperties(NumberPrototype, {
1142 toFixed: function toFixed(fractionDigits) {
1143 var f, x, s, m, e, z, j, k;
1144
1145 // Test for NaN and round fractionDigits down
1146 f = Number(fractionDigits);
1147 f = f !== f ? 0 : Math.floor(f);
1148
1149 if (f < 0 || f > 20) {
1150 throw new RangeError("Number.toFixed called with invalid number of decimals");
1151 }
1152
1153 x = Number(this);
1154
1155 // Test for NaN
1156 if (x !== x) {
1157 return "NaN";
1158 }
1159
1160 // If it is too big or small, return the string value of the number
1161 if (x <= -1e21 || x >= 1e21) {
1162 return String(x);
1163 }
1164
1165 s = "";
1166
1167 if (x < 0) {
1168 s = "-";
1169 x = -x;
1170 }
1171
1172 m = "0";
1173
1174 if (x > 1e-21) {
1175 // 1e-21 < x < 1e21
1176 // -70 < log2(x) < 70
1177 e = toFixedHelpers.log(x * toFixedHelpers.pow(2, 69, 1)) - 69;
1178 z = (e < 0 ? x * toFixedHelpers.pow(2, -e, 1) : x / toFixedHelpers.pow(2, e, 1));
1179 z *= 0x10000000000000; // Math.pow(2, 52);
1180 e = 52 - e;
1181
1182 // -18 < e < 122
1183 // x = z / 2 ^ e
1184 if (e > 0) {
1185 toFixedHelpers.multiply(0, z);
1186 j = f;
1187
1188 while (j >= 7) {
1189 toFixedHelpers.multiply(1e7, 0);
1190 j -= 7;
1191 }
1192
1193 toFixedHelpers.multiply(toFixedHelpers.pow(10, j, 1), 0);
1194 j = e - 1;
1195
1196 while (j >= 23) {
1197 toFixedHelpers.divide(1 << 23);
1198 j -= 23;
1199 }
1200
1201 toFixedHelpers.divide(1 << j);
1202 toFixedHelpers.multiply(1, 1);
1203 toFixedHelpers.divide(2);
1204 m = toFixedHelpers.numToString();
1205 } else {
1206 toFixedHelpers.multiply(0, z);
1207 toFixedHelpers.multiply(1 << (-e), 0);
1208 m = toFixedHelpers.numToString() + '0.00000000000000000000'.slice(2, 2 + f);
1209 }
1210 }
1211
1212 if (f > 0) {
1213 k = m.length;
1214
1215 if (k <= f) {
1216 m = s + '0.0000000000000000000'.slice(0, f - k + 2) + m;
1217 } else {
1218 m = s + m.slice(0, k - f) + '.' + m.slice(k - f);
1219 }
1220 } else {
1221 m = s + m;
1222 }
1223
1224 return m;
1225 }
1226 }, hasToFixedBugs);
1227
1228
1229 //
1230 // String
1231 // ======
1232 //
1233
1234 // ES5 15.5.4.14
1235 // http://es5.github.com/#x15.5.4.14
1236
1237 // [bugfix, IE lt 9, firefox 4, Konqueror, Opera, obscure browsers]
1238 // Many browsers do not split properly with regular expressions or they
1239 // do not perform the split correctly under obscure conditions.
1240 // See http://blog.stevenlevithan.com/archives/cross-browser-split
1241 // I've tested in many browsers and this seems to cover the deviant ones:
1242 // 'ab'.split(/(?:ab)*/) should be ["", ""], not [""]
1243 // '.'.split(/(.?)(.?)/) should be ["", ".", "", ""], not ["", ""]
1244 // 'tesst'.split(/(s)*/) should be ["t", undefined, "e", "s", "t"], not
1245 // [undefined, "t", undefined, "e", ...]
1246 // ''.split(/.?/) should be [], not [""]
1247 // '.'.split(/()()/) should be ["."], not ["", "", "."]
1248
1249 var string_split = StringPrototype.split;
1250 if (
1251 'ab'.split(/(?:ab)*/).length !== 2 ||
1252 '.'.split(/(.?)(.?)/).length !== 4 ||
1253 'tesst'.split(/(s)*/)[1] === "t" ||
1254 'test'.split(/(?:)/, -1).length !== 4 ||
1255 ''.split(/.?/).length ||
1256 '.'.split(/()()/).length > 1
1257 ) {
1258 (function () {
1259 var compliantExecNpcg = /()??/.exec("")[1] === void 0; // NPCG: nonparticipating capturing group
1260
1261 StringPrototype.split = function (separator, limit) {
1262 var string = this;
1263 if (separator === void 0 && limit === 0) {
1264 return [];
1265 }
1266
1267 // If `separator` is not a regex, use native split
1268 if (_toString.call(separator) !== "[object RegExp]") {
1269 return string_split.call(this, separator, limit);
1270 }
1271
1272 var output = [],
1273 flags = (separator.ignoreCase ? "i" : "") +
1274 (separator.multiline ? "m" : "") +
1275 (separator.extended ? "x" : "") + // Proposed for ES6
1276 (separator.sticky ? "y" : ""), // Firefox 3+
1277 lastLastIndex = 0,
1278 // Make `global` and avoid `lastIndex` issues by working with a copy
1279 separator2, match, lastIndex, lastLength;
1280 separator = new RegExp(separator.source, flags + "g");
1281 string += ""; // Type-convert
1282 if (!compliantExecNpcg) {
1283 // Doesn't need flags gy, but they don't hurt
1284 separator2 = new RegExp("^" + separator.source + "$(?!\\s)", flags);
1285 }
1286 /* Values for `limit`, per the spec:
1287 * If undefined: 4294967295 // Math.pow(2, 32) - 1
1288 * If 0, Infinity, or NaN: 0
1289 * If positive number: limit = Math.floor(limit); if (limit > 4294967295) limit -= 4294967296;
1290 * If negative number: 4294967296 - Math.floor(Math.abs(limit))
1291 * If other: Type-convert, then use the above rules
1292 */
1293 limit = limit === void 0 ?
1294 -1 >>> 0 : // Math.pow(2, 32) - 1
1295 ToUint32(limit);
1296 while (match = separator.exec(string)) {
1297 // `separator.lastIndex` is not reliable cross-browser
1298 lastIndex = match.index + match[0].length;
1299 if (lastIndex > lastLastIndex) {
1300 output.push(string.slice(lastLastIndex, match.index));
1301 // Fix browsers whose `exec` methods don't consistently return `undefined` for
1302 // nonparticipating capturing groups
1303 if (!compliantExecNpcg && match.length > 1) {
1304 match[0].replace(separator2, function () {
1305 for (var i = 1; i < arguments.length - 2; i++) {
1306 if (arguments[i] === void 0) {
1307 match[i] = void 0;
1308 }
1309 }
1310 });
1311 }
1312 if (match.length > 1 && match.index < string.length) {
1313 ArrayPrototype.push.apply(output, match.slice(1));
1314 }
1315 lastLength = match[0].length;
1316 lastLastIndex = lastIndex;
1317 if (output.length >= limit) {
1318 break;
1319 }
1320 }
1321 if (separator.lastIndex === match.index) {
1322 separator.lastIndex++; // Avoid an infinite loop
1323 }
1324 }
1325 if (lastLastIndex === string.length) {
1326 if (lastLength || !separator.test("")) {
1327 output.push("");
1328 }
1329 } else {
1330 output.push(string.slice(lastLastIndex));
1331 }
1332 return output.length > limit ? output.slice(0, limit) : output;
1333 };
1334 }());
1335
1336 // [bugfix, chrome]
1337 // If separator is undefined, then the result array contains just one String,
1338 // which is the this value (converted to a String). If limit is not undefined,
1339 // then the output array is truncated so that it contains no more than limit
1340 // elements.
1341 // "0".split(undefined, 0) -> []
1342 } else if ("0".split(void 0, 0).length) {
1343 StringPrototype.split = function split(separator, limit) {
1344 if (separator === void 0 && limit === 0) { return []; }
1345 return string_split.call(this, separator, limit);
1346 };
1347 }
1348
1349 var str_replace = StringPrototype.replace;
1350 var replaceReportsGroupsCorrectly = (function () {
1351 var groups = [];
1352 'x'.replace(/x(.)?/g, function (match, group) {
1353 groups.push(group);
1354 });
1355 return groups.length === 1 && typeof groups[0] === 'undefined';
1356 }());
1357
1358 if (!replaceReportsGroupsCorrectly) {
1359 StringPrototype.replace = function replace(searchValue, replaceValue) {
1360 var isFn = isFunction(replaceValue);
1361 var hasCapturingGroups = isRegex(searchValue) && (/\)[*?]/).test(searchValue.source);
1362 if (!isFn || !hasCapturingGroups) {
1363 return str_replace.call(this, searchValue, replaceValue);
1364 } else {
1365 var wrappedReplaceValue = function (match) {
1366 var length = arguments.length;
1367 var originalLastIndex = searchValue.lastIndex;
1368 searchValue.lastIndex = 0;
1369 var args = searchValue.exec(match);
1370 searchValue.lastIndex = originalLastIndex;
1371 args.push(arguments[length - 2], arguments[length - 1]);
1372 return replaceValue.apply(this, args);
1373 };
1374 return str_replace.call(this, searchValue, wrappedReplaceValue);
1375 }
1376 };
1377 }
1378
1379 // ECMA-262, 3rd B.2.3
1380 // Not an ECMAScript standard, although ECMAScript 3rd Edition has a
1381 // non-normative section suggesting uniform semantics and it should be
1382 // normalized across all browsers
1383 // [bugfix, IE lt 9] IE < 9 substr() with negative value not working in IE
1384 var string_substr = StringPrototype.substr;
1385 var hasNegativeSubstrBug = "".substr && "0b".substr(-1) !== "b";
1386 defineProperties(StringPrototype, {
1387 substr: function substr(start, length) {
1388 return string_substr.call(
1389 this,
1390 start < 0 ? ((start = this.length + start) < 0 ? 0 : start) : start,
1391 length
1392 );
1393 }
1394 }, hasNegativeSubstrBug);
1395
1396 // ES5 15.5.4.20
1397 // whitespace from: http://es5.github.io/#x15.5.4.20
1398 var ws = "\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003" +
1399 "\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028" +
1400 "\u2029\uFEFF";
1401 var zeroWidth = '\u200b';
1402 var wsRegexChars = "[" + ws + "]";
1403 var trimBeginRegexp = new RegExp("^" + wsRegexChars + wsRegexChars + "*");
1404 var trimEndRegexp = new RegExp(wsRegexChars + wsRegexChars + "*$");
1405 var hasTrimWhitespaceBug = StringPrototype.trim && (ws.trim() || !zeroWidth.trim());
1406 defineProperties(StringPrototype, {
1407 // http://blog.stevenlevithan.com/archives/faster-trim-javascript
1408 // http://perfectionkills.com/whitespace-deviations/
1409 trim: function trim() {
1410 if (this === void 0 || this === null) {
1411 throw new TypeError("can't convert " + this + " to object");
1412 }
1413 return String(this).replace(trimBeginRegexp, "").replace(trimEndRegexp, "");
1414 }
1415 }, hasTrimWhitespaceBug);
1416
1417 // ES-5 15.1.2.2
1418 if (parseInt(ws + '08') !== 8 || parseInt(ws + '0x16') !== 22) {
1419 parseInt = (function (origParseInt) {
1420 var hexRegex = /^0[xX]/;
1421 return function parseIntES5(str, radix) {
1422 str = String(str).trim();
1423 if (!Number(radix)) {
1424 radix = hexRegex.test(str) ? 16 : 10;
1425 }
1426 return origParseInt(str, radix);
1427 };
1428 }(parseInt));
1429 }
1430
1431 }));