Projekt

Obecné

Profil

Stáhnout (42.1 KB) Statistiky
| Větev: | Revize:
1 3a515b92 cagy
/*! JSON v3.3.2 | https://bestiejs.github.io/json3 | Copyright 2012-2015, Kit Cambridge, Benjamin Tan | http://kit.mit-license.org */
2
;(function () {
3
  // Detect the `define` function exposed by asynchronous module loaders. The
4
  // strict `define` check is necessary for compatibility with `r.js`.
5
  var isLoader = typeof define === "function" && define.amd;
6
7
  // A set of types used to distinguish objects from primitives.
8
  var objectTypes = {
9
    "function": true,
10
    "object": true
11
  };
12
13
  // Detect the `exports` object exposed by CommonJS implementations.
14
  var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports;
15
16
  // Use the `global` object exposed by Node (including Browserify via
17
  // `insert-module-globals`), Narwhal, and Ringo as the default context,
18
  // and the `window` object in browsers. Rhino exports a `global` function
19
  // instead.
20
  var root = objectTypes[typeof window] && window || this,
21
      freeGlobal = freeExports && objectTypes[typeof module] && module && !module.nodeType && typeof global == "object" && global;
22
23
  if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal || freeGlobal.self === freeGlobal)) {
24
    root = freeGlobal;
25
  }
26
27
  // Public: Initializes JSON 3 using the given `context` object, attaching the
28
  // `stringify` and `parse` functions to the specified `exports` object.
29
  function runInContext(context, exports) {
30
    context || (context = root.Object());
31
    exports || (exports = root.Object());
32
33
    // Native constructor aliases.
34
    var Number = context.Number || root.Number,
35
        String = context.String || root.String,
36
        Object = context.Object || root.Object,
37
        Date = context.Date || root.Date,
38
        SyntaxError = context.SyntaxError || root.SyntaxError,
39
        TypeError = context.TypeError || root.TypeError,
40
        Math = context.Math || root.Math,
41
        nativeJSON = context.JSON || root.JSON;
42
43
    // Delegate to the native `stringify` and `parse` implementations.
44
    if (typeof nativeJSON == "object" && nativeJSON) {
45
      exports.stringify = nativeJSON.stringify;
46
      exports.parse = nativeJSON.parse;
47
    }
48
49
    // Convenience aliases.
50
    var objectProto = Object.prototype,
51
        getClass = objectProto.toString,
52
        isProperty = objectProto.hasOwnProperty,
53
        undefined;
54
55
    // Internal: Contains `try...catch` logic used by other functions.
56
    // This prevents other functions from being deoptimized.
57
    function attempt(func, errorFunc) {
58
      try {
59
        func();
60
      } catch (exception) {
61
        if (errorFunc) {
62
          errorFunc();
63
        }
64
      }
65
    }
66
67
    // Test the `Date#getUTC*` methods. Based on work by @Yaffle.
68
    var isExtended = new Date(-3509827334573292);
69
    attempt(function () {
70
      // The `getUTCFullYear`, `Month`, and `Date` methods return nonsensical
71
      // results for certain dates in Opera >= 10.53.
72
      isExtended = isExtended.getUTCFullYear() == -109252 && isExtended.getUTCMonth() === 0 && isExtended.getUTCDate() === 1 &&
73
        isExtended.getUTCHours() == 10 && isExtended.getUTCMinutes() == 37 && isExtended.getUTCSeconds() == 6 && isExtended.getUTCMilliseconds() == 708;
74
    });
75
76
    // Internal: Determines whether the native `JSON.stringify` and `parse`
77
    // implementations are spec-compliant. Based on work by Ken Snyder.
78
    function has(name) {
79
      if (has[name] != null) {
80
        // Return cached feature test result.
81
        return has[name];
82
      }
83
      var isSupported;
84
      if (name == "bug-string-char-index") {
85
        // IE <= 7 doesn't support accessing string characters using square
86
        // bracket notation. IE 8 only supports this for primitives.
87
        isSupported = "a"[0] != "a";
88
      } else if (name == "json") {
89
        // Indicates whether both `JSON.stringify` and `JSON.parse` are
90
        // supported.
91
        isSupported = has("json-stringify") && has("date-serialization") && has("json-parse");
92
      } else if (name == "date-serialization") {
93
        // Indicates whether `Date`s can be serialized accurately by `JSON.stringify`.
94
        isSupported = has("json-stringify") && isExtended;
95
        if (isSupported) {
96
          var stringify = exports.stringify;
97
          attempt(function () {
98
            isSupported =
99
              // JSON 2, Prototype <= 1.7, and older WebKit builds incorrectly
100
              // serialize extended years.
101
              stringify(new Date(-8.64e15)) == '"-271821-04-20T00:00:00.000Z"' &&
102
              // The milliseconds are optional in ES 5, but required in 5.1.
103
              stringify(new Date(8.64e15)) == '"+275760-09-13T00:00:00.000Z"' &&
104
              // Firefox <= 11.0 incorrectly serializes years prior to 0 as negative
105
              // four-digit years instead of six-digit years. Credits: @Yaffle.
106
              stringify(new Date(-621987552e5)) == '"-000001-01-01T00:00:00.000Z"' &&
107
              // Safari <= 5.1.5 and Opera >= 10.53 incorrectly serialize millisecond
108
              // values less than 1000. Credits: @Yaffle.
109
              stringify(new Date(-1)) == '"1969-12-31T23:59:59.999Z"';
110
          });
111
        }
112
      } else {
113
        var value, serialized = '{"a":[1,true,false,null,"\\u0000\\b\\n\\f\\r\\t"]}';
114
        // Test `JSON.stringify`.
115
        if (name == "json-stringify") {
116
          var stringify = exports.stringify, stringifySupported = typeof stringify == "function";
117
          if (stringifySupported) {
118
            // A test function object with a custom `toJSON` method.
119
            (value = function () {
120
              return 1;
121
            }).toJSON = value;
122
            attempt(function () {
123
              stringifySupported =
124
                // Firefox 3.1b1 and b2 serialize string, number, and boolean
125
                // primitives as object literals.
126
                stringify(0) === "0" &&
127
                // FF 3.1b1, b2, and JSON 2 serialize wrapped primitives as object
128
                // literals.
129
                stringify(new Number()) === "0" &&
130
                stringify(new String()) == '""' &&
131
                // FF 3.1b1, 2 throw an error if the value is `null`, `undefined`, or
132
                // does not define a canonical JSON representation (this applies to
133
                // objects with `toJSON` properties as well, *unless* they are nested
134
                // within an object or array).
135
                stringify(getClass) === undefined &&
136
                // IE 8 serializes `undefined` as `"undefined"`. Safari <= 5.1.7 and
137
                // FF 3.1b3 pass this test.
138
                stringify(undefined) === undefined &&
139
                // Safari <= 5.1.7 and FF 3.1b3 throw `Error`s and `TypeError`s,
140
                // respectively, if the value is omitted entirely.
141
                stringify() === undefined &&
142
                // FF 3.1b1, 2 throw an error if the given value is not a number,
143
                // string, array, object, Boolean, or `null` literal. This applies to
144
                // objects with custom `toJSON` methods as well, unless they are nested
145
                // inside object or array literals. YUI 3.0.0b1 ignores custom `toJSON`
146
                // methods entirely.
147
                stringify(value) === "1" &&
148
                stringify([value]) == "[1]" &&
149
                // Prototype <= 1.6.1 serializes `[undefined]` as `"[]"` instead of
150
                // `"[null]"`.
151
                stringify([undefined]) == "[null]" &&
152
                // YUI 3.0.0b1 fails to serialize `null` literals.
153
                stringify(null) == "null" &&
154
                // FF 3.1b1, 2 halts serialization if an array contains a function:
155
                // `[1, true, getClass, 1]` serializes as "[1,true,],". FF 3.1b3
156
                // elides non-JSON values from objects and arrays, unless they
157
                // define custom `toJSON` methods.
158
                stringify([undefined, getClass, null]) == "[null,null,null]" &&
159
                // Simple serialization test. FF 3.1b1 uses Unicode escape sequences
160
                // where character escape codes are expected (e.g., `\b` => `\u0008`).
161
                stringify({ "a": [value, true, false, null, "\x00\b\n\f\r\t"] }) == serialized &&
162
                // FF 3.1b1 and b2 ignore the `filter` and `width` arguments.
163
                stringify(null, value) === "1" &&
164
                stringify([1, 2], null, 1) == "[\n 1,\n 2\n]";
165
            }, function () {
166
              stringifySupported = false;
167
            });
168
          }
169
          isSupported = stringifySupported;
170
        }
171
        // Test `JSON.parse`.
172
        if (name == "json-parse") {
173
          var parse = exports.parse, parseSupported;
174
          if (typeof parse == "function") {
175
            attempt(function () {
176
              // FF 3.1b1, b2 will throw an exception if a bare literal is provided.
177
              // Conforming implementations should also coerce the initial argument to
178
              // a string prior to parsing.
179
              if (parse("0") === 0 && !parse(false)) {
180
                // Simple parsing test.
181
                value = parse(serialized);
182
                parseSupported = value["a"].length == 5 && value["a"][0] === 1;
183
                if (parseSupported) {
184
                  attempt(function () {
185
                    // Safari <= 5.1.2 and FF 3.1b1 allow unescaped tabs in strings.
186
                    parseSupported = !parse('"\t"');
187
                  });
188
                  if (parseSupported) {
189
                    attempt(function () {
190
                      // FF 4.0 and 4.0.1 allow leading `+` signs and leading
191
                      // decimal points. FF 4.0, 4.0.1, and IE 9-10 also allow
192
                      // certain octal literals.
193
                      parseSupported = parse("01") !== 1;
194
                    });
195
                  }
196
                  if (parseSupported) {
197
                    attempt(function () {
198
                      // FF 4.0, 4.0.1, and Rhino 1.7R3-R4 allow trailing decimal
199
                      // points. These environments, along with FF 3.1b1 and 2,
200
                      // also allow trailing commas in JSON objects and arrays.
201
                      parseSupported = parse("1.") !== 1;
202
                    });
203
                  }
204
                }
205
              }
206
            }, function () {
207
              parseSupported = false;
208
            });
209
          }
210
          isSupported = parseSupported;
211
        }
212
      }
213
      return has[name] = !!isSupported;
214
    }
215
    has["bug-string-char-index"] = has["date-serialization"] = has["json"] = has["json-stringify"] = has["json-parse"] = null;
216
217
    if (!has("json")) {
218
      // Common `[[Class]]` name aliases.
219
      var functionClass = "[object Function]",
220
          dateClass = "[object Date]",
221
          numberClass = "[object Number]",
222
          stringClass = "[object String]",
223
          arrayClass = "[object Array]",
224
          booleanClass = "[object Boolean]";
225
226
      // Detect incomplete support for accessing string characters by index.
227
      var charIndexBuggy = has("bug-string-char-index");
228
229
      // Internal: Normalizes the `for...in` iteration algorithm across
230
      // environments. Each enumerated key is yielded to a `callback` function.
231
      var forOwn = function (object, callback) {
232
        var size = 0, Properties, dontEnums, property;
233
234
        // Tests for bugs in the current environment's `for...in` algorithm. The
235
        // `valueOf` property inherits the non-enumerable flag from
236
        // `Object.prototype` in older versions of IE, Netscape, and Mozilla.
237
        (Properties = function () {
238
          this.valueOf = 0;
239
        }).prototype.valueOf = 0;
240
241
        // Iterate over a new instance of the `Properties` class.
242
        dontEnums = new Properties();
243
        for (property in dontEnums) {
244
          // Ignore all properties inherited from `Object.prototype`.
245
          if (isProperty.call(dontEnums, property)) {
246
            size++;
247
          }
248
        }
249
        Properties = dontEnums = null;
250
251
        // Normalize the iteration algorithm.
252
        if (!size) {
253
          // A list of non-enumerable properties inherited from `Object.prototype`.
254
          dontEnums = ["valueOf", "toString", "toLocaleString", "propertyIsEnumerable", "isPrototypeOf", "hasOwnProperty", "constructor"];
255
          // IE <= 8, Mozilla 1.0, and Netscape 6.2 ignore shadowed non-enumerable
256
          // properties.
257
          forOwn = function (object, callback) {
258
            var isFunction = getClass.call(object) == functionClass, property, length;
259
            var hasProperty = !isFunction && typeof object.constructor != "function" && objectTypes[typeof object.hasOwnProperty] && object.hasOwnProperty || isProperty;
260
            for (property in object) {
261
              // Gecko <= 1.0 enumerates the `prototype` property of functions under
262
              // certain conditions; IE does not.
263
              if (!(isFunction && property == "prototype") && hasProperty.call(object, property)) {
264
                callback(property);
265
              }
266
            }
267
            // Manually invoke the callback for each non-enumerable property.
268
            for (length = dontEnums.length; property = dontEnums[--length];) {
269
              if (hasProperty.call(object, property)) {
270
                callback(property);
271
              }
272
            }
273
          };
274
        } else {
275
          // No bugs detected; use the standard `for...in` algorithm.
276
          forOwn = function (object, callback) {
277
            var isFunction = getClass.call(object) == functionClass, property, isConstructor;
278
            for (property in object) {
279
              if (!(isFunction && property == "prototype") && isProperty.call(object, property) && !(isConstructor = property === "constructor")) {
280
                callback(property);
281
              }
282
            }
283
            // Manually invoke the callback for the `constructor` property due to
284
            // cross-environment inconsistencies.
285
            if (isConstructor || isProperty.call(object, (property = "constructor"))) {
286
              callback(property);
287
            }
288
          };
289
        }
290
        return forOwn(object, callback);
291
      };
292
293
      // Public: Serializes a JavaScript `value` as a JSON string. The optional
294
      // `filter` argument may specify either a function that alters how object and
295
      // array members are serialized, or an array of strings and numbers that
296
      // indicates which properties should be serialized. The optional `width`
297
      // argument may be either a string or number that specifies the indentation
298
      // level of the output.
299
      if (!has("json-stringify") && !has("date-serialization")) {
300
        // Internal: A map of control characters and their escaped equivalents.
301
        var Escapes = {
302
          92: "\\\\",
303
          34: '\\"',
304
          8: "\\b",
305
          12: "\\f",
306
          10: "\\n",
307
          13: "\\r",
308
          9: "\\t"
309
        };
310
311
        // Internal: Converts `value` into a zero-padded string such that its
312
        // length is at least equal to `width`. The `width` must be <= 6.
313
        var leadingZeroes = "000000";
314
        var toPaddedString = function (width, value) {
315
          // The `|| 0` expression is necessary to work around a bug in
316
          // Opera <= 7.54u2 where `0 == -0`, but `String(-0) !== "0"`.
317
          return (leadingZeroes + (value || 0)).slice(-width);
318
        };
319
320
        // Internal: Serializes a date object.
321
        var serializeDate = function (value) {
322
          var getData, year, month, date, time, hours, minutes, seconds, milliseconds;
323
          // Define additional utility methods if the `Date` methods are buggy.
324
          if (!isExtended) {
325
            var floor = Math.floor;
326
            // A mapping between the months of the year and the number of days between
327
            // January 1st and the first of the respective month.
328
            var Months = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334];
329
            // Internal: Calculates the number of days between the Unix epoch and the
330
            // first day of the given month.
331
            var getDay = function (year, month) {
332
              return Months[month] + 365 * (year - 1970) + floor((year - 1969 + (month = +(month > 1))) / 4) - floor((year - 1901 + month) / 100) + floor((year - 1601 + month) / 400);
333
            };
334
            getData = function (value) {
335
              // Manually compute the year, month, date, hours, minutes,
336
              // seconds, and milliseconds if the `getUTC*` methods are
337
              // buggy. Adapted from @Yaffle's `date-shim` project.
338
              date = floor(value / 864e5);
339
              for (year = floor(date / 365.2425) + 1970 - 1; getDay(year + 1, 0) <= date; year++);
340
              for (month = floor((date - getDay(year, 0)) / 30.42); getDay(year, month + 1) <= date; month++);
341
              date = 1 + date - getDay(year, month);
342
              // The `time` value specifies the time within the day (see ES
343
              // 5.1 section 15.9.1.2). The formula `(A % B + B) % B` is used
344
              // to compute `A modulo B`, as the `%` operator does not
345
              // correspond to the `modulo` operation for negative numbers.
346
              time = (value % 864e5 + 864e5) % 864e5;
347
              // The hours, minutes, seconds, and milliseconds are obtained by
348
              // decomposing the time within the day. See section 15.9.1.10.
349
              hours = floor(time / 36e5) % 24;
350
              minutes = floor(time / 6e4) % 60;
351
              seconds = floor(time / 1e3) % 60;
352
              milliseconds = time % 1e3;
353
            };
354
          } else {
355
            getData = function (value) {
356
              year = value.getUTCFullYear();
357
              month = value.getUTCMonth();
358
              date = value.getUTCDate();
359
              hours = value.getUTCHours();
360
              minutes = value.getUTCMinutes();
361
              seconds = value.getUTCSeconds();
362
              milliseconds = value.getUTCMilliseconds();
363
            };
364
          }
365
          serializeDate = function (value) {
366
            if (value > -1 / 0 && value < 1 / 0) {
367
              // Dates are serialized according to the `Date#toJSON` method
368
              // specified in ES 5.1 section 15.9.5.44. See section 15.9.1.15
369
              // for the ISO 8601 date time string format.
370
              getData(value);
371
              // Serialize extended years correctly.
372
              value = (year <= 0 || year >= 1e4 ? (year < 0 ? "-" : "+") + toPaddedString(6, year < 0 ? -year : year) : toPaddedString(4, year)) +
373
              "-" + toPaddedString(2, month + 1) + "-" + toPaddedString(2, date) +
374
              // Months, dates, hours, minutes, and seconds should have two
375
              // digits; milliseconds should have three.
376
              "T" + toPaddedString(2, hours) + ":" + toPaddedString(2, minutes) + ":" + toPaddedString(2, seconds) +
377
              // Milliseconds are optional in ES 5.0, but required in 5.1.
378
              "." + toPaddedString(3, milliseconds) + "Z";
379
              year = month = date = hours = minutes = seconds = milliseconds = null;
380
            } else {
381
              value = null;
382
            }
383
            return value;
384
          };
385
          return serializeDate(value);
386
        };
387
388
        // For environments with `JSON.stringify` but buggy date serialization,
389
        // we override the native `Date#toJSON` implementation with a
390
        // spec-compliant one.
391
        if (has("json-stringify") && !has("date-serialization")) {
392
          // Internal: the `Date#toJSON` implementation used to override the native one.
393
          function dateToJSON (key) {
394
            return serializeDate(this);
395
          }
396
397
          // Public: `JSON.stringify`. See ES 5.1 section 15.12.3.
398
          var nativeStringify = exports.stringify;
399
          exports.stringify = function (source, filter, width) {
400
            var nativeToJSON = Date.prototype.toJSON;
401
            Date.prototype.toJSON = dateToJSON;
402
            var result = nativeStringify(source, filter, width);
403
            Date.prototype.toJSON = nativeToJSON;
404
            return result;
405
          }
406
        } else {
407
          // Internal: Double-quotes a string `value`, replacing all ASCII control
408
          // characters (characters with code unit values between 0 and 31) with
409
          // their escaped equivalents. This is an implementation of the
410
          // `Quote(value)` operation defined in ES 5.1 section 15.12.3.
411
          var unicodePrefix = "\\u00";
412
          var escapeChar = function (character) {
413
            var charCode = character.charCodeAt(0), escaped = Escapes[charCode];
414
            if (escaped) {
415
              return escaped;
416
            }
417
            return unicodePrefix + toPaddedString(2, charCode.toString(16));
418
          };
419
          var reEscape = /[\x00-\x1f\x22\x5c]/g;
420
          var quote = function (value) {
421
            reEscape.lastIndex = 0;
422
            return '"' +
423
              (
424
                reEscape.test(value)
425
                  ? value.replace(reEscape, escapeChar)
426
                  : value
427
              ) +
428
              '"';
429
          };
430
431
          // Internal: Recursively serializes an object. Implements the
432
          // `Str(key, holder)`, `JO(value)`, and `JA(value)` operations.
433
          var serialize = function (property, object, callback, properties, whitespace, indentation, stack) {
434
            var value, type, className, results, element, index, length, prefix, result;
435
            attempt(function () {
436
              // Necessary for host object support.
437
              value = object[property];
438
            });
439
            if (typeof value == "object" && value) {
440
              if (value.getUTCFullYear && getClass.call(value) == dateClass && value.toJSON === Date.prototype.toJSON) {
441
                value = serializeDate(value);
442
              } else if (typeof value.toJSON == "function") {
443
                value = value.toJSON(property);
444
              }
445
            }
446
            if (callback) {
447
              // If a replacement function was provided, call it to obtain the value
448
              // for serialization.
449
              value = callback.call(object, property, value);
450
            }
451
            // Exit early if value is `undefined` or `null`.
452
            if (value == undefined) {
453
              return value === undefined ? value : "null";
454
            }
455
            type = typeof value;
456
            // Only call `getClass` if the value is an object.
457
            if (type == "object") {
458
              className = getClass.call(value);
459
            }
460
            switch (className || type) {
461
              case "boolean":
462
              case booleanClass:
463
                // Booleans are represented literally.
464
                return "" + value;
465
              case "number":
466
              case numberClass:
467
                // JSON numbers must be finite. `Infinity` and `NaN` are serialized as
468
                // `"null"`.
469
                return value > -1 / 0 && value < 1 / 0 ? "" + value : "null";
470
              case "string":
471
              case stringClass:
472
                // Strings are double-quoted and escaped.
473
                return quote("" + value);
474
            }
475
            // Recursively serialize objects and arrays.
476
            if (typeof value == "object") {
477
              // Check for cyclic structures. This is a linear search; performance
478
              // is inversely proportional to the number of unique nested objects.
479
              for (length = stack.length; length--;) {
480
                if (stack[length] === value) {
481
                  // Cyclic structures cannot be serialized by `JSON.stringify`.
482
                  throw TypeError();
483
                }
484
              }
485
              // Add the object to the stack of traversed objects.
486
              stack.push(value);
487
              results = [];
488
              // Save the current indentation level and indent one additional level.
489
              prefix = indentation;
490
              indentation += whitespace;
491
              if (className == arrayClass) {
492
                // Recursively serialize array elements.
493
                for (index = 0, length = value.length; index < length; index++) {
494
                  element = serialize(index, value, callback, properties, whitespace, indentation, stack);
495
                  results.push(element === undefined ? "null" : element);
496
                }
497
                result = results.length ? (whitespace ? "[\n" + indentation + results.join(",\n" + indentation) + "\n" + prefix + "]" : ("[" + results.join(",") + "]")) : "[]";
498
              } else {
499
                // Recursively serialize object members. Members are selected from
500
                // either a user-specified list of property names, or the object
501
                // itself.
502
                forOwn(properties || value, function (property) {
503
                  var element = serialize(property, value, callback, properties, whitespace, indentation, stack);
504
                  if (element !== undefined) {
505
                    // According to ES 5.1 section 15.12.3: "If `gap` {whitespace}
506
                    // is not the empty string, let `member` {quote(property) + ":"}
507
                    // be the concatenation of `member` and the `space` character."
508
                    // The "`space` character" refers to the literal space
509
                    // character, not the `space` {width} argument provided to
510
                    // `JSON.stringify`.
511
                    results.push(quote(property) + ":" + (whitespace ? " " : "") + element);
512
                  }
513
                });
514
                result = results.length ? (whitespace ? "{\n" + indentation + results.join(",\n" + indentation) + "\n" + prefix + "}" : ("{" + results.join(",") + "}")) : "{}";
515
              }
516
              // Remove the object from the traversed object stack.
517
              stack.pop();
518
              return result;
519
            }
520
          };
521
522
          // Public: `JSON.stringify`. See ES 5.1 section 15.12.3.
523
          exports.stringify = function (source, filter, width) {
524
            var whitespace, callback, properties, className;
525
            if (objectTypes[typeof filter] && filter) {
526
              className = getClass.call(filter);
527
              if (className == functionClass) {
528
                callback = filter;
529
              } else if (className == arrayClass) {
530
                // Convert the property names array into a makeshift set.
531
                properties = {};
532
                for (var index = 0, length = filter.length, value; index < length;) {
533
                  value = filter[index++];
534
                  className = getClass.call(value);
535
                  if (className == "[object String]" || className == "[object Number]") {
536
                    properties[value] = 1;
537
                  }
538
                }
539
              }
540
            }
541
            if (width) {
542
              className = getClass.call(width);
543
              if (className == numberClass) {
544
                // Convert the `width` to an integer and create a string containing
545
                // `width` number of space characters.
546
                if ((width -= width % 1) > 0) {
547
                  if (width > 10) {
548
                    width = 10;
549
                  }
550
                  for (whitespace = ""; whitespace.length < width;) {
551
                    whitespace += " ";
552
                  }
553
                }
554
              } else if (className == stringClass) {
555
                whitespace = width.length <= 10 ? width : width.slice(0, 10);
556
              }
557
            }
558
            // Opera <= 7.54u2 discards the values associated with empty string keys
559
            // (`""`) only if they are used directly within an object member list
560
            // (e.g., `!("" in { "": 1})`).
561
            return serialize("", (value = {}, value[""] = source, value), callback, properties, whitespace, "", []);
562
          };
563
        }
564
      }
565
566
      // Public: Parses a JSON source string.
567
      if (!has("json-parse")) {
568
        var fromCharCode = String.fromCharCode;
569
570
        // Internal: A map of escaped control characters and their unescaped
571
        // equivalents.
572
        var Unescapes = {
573
          92: "\\",
574
          34: '"',
575
          47: "/",
576
          98: "\b",
577
          116: "\t",
578
          110: "\n",
579
          102: "\f",
580
          114: "\r"
581
        };
582
583
        // Internal: Stores the parser state.
584
        var Index, Source;
585
586
        // Internal: Resets the parser state and throws a `SyntaxError`.
587
        var abort = function () {
588
          Index = Source = null;
589
          throw SyntaxError();
590
        };
591
592
        // Internal: Returns the next token, or `"$"` if the parser has reached
593
        // the end of the source string. A token may be a string, number, `null`
594
        // literal, or Boolean literal.
595
        var lex = function () {
596
          var source = Source, length = source.length, value, begin, position, isSigned, charCode;
597
          while (Index < length) {
598
            charCode = source.charCodeAt(Index);
599
            switch (charCode) {
600
              case 9: case 10: case 13: case 32:
601
                // Skip whitespace tokens, including tabs, carriage returns, line
602
                // feeds, and space characters.
603
                Index++;
604
                break;
605
              case 123: case 125: case 91: case 93: case 58: case 44:
606
                // Parse a punctuator token (`{`, `}`, `[`, `]`, `:`, or `,`) at
607
                // the current position.
608
                value = charIndexBuggy ? source.charAt(Index) : source[Index];
609
                Index++;
610
                return value;
611
              case 34:
612
                // `"` delimits a JSON string; advance to the next character and
613
                // begin parsing the string. String tokens are prefixed with the
614
                // sentinel `@` character to distinguish them from punctuators and
615
                // end-of-string tokens.
616
                for (value = "@", Index++; Index < length;) {
617
                  charCode = source.charCodeAt(Index);
618
                  if (charCode < 32) {
619
                    // Unescaped ASCII control characters (those with a code unit
620
                    // less than the space character) are not permitted.
621
                    abort();
622
                  } else if (charCode == 92) {
623
                    // A reverse solidus (`\`) marks the beginning of an escaped
624
                    // control character (including `"`, `\`, and `/`) or Unicode
625
                    // escape sequence.
626
                    charCode = source.charCodeAt(++Index);
627
                    switch (charCode) {
628
                      case 92: case 34: case 47: case 98: case 116: case 110: case 102: case 114:
629
                        // Revive escaped control characters.
630
                        value += Unescapes[charCode];
631
                        Index++;
632
                        break;
633
                      case 117:
634
                        // `\u` marks the beginning of a Unicode escape sequence.
635
                        // Advance to the first character and validate the
636
                        // four-digit code point.
637
                        begin = ++Index;
638
                        for (position = Index + 4; Index < position; Index++) {
639
                          charCode = source.charCodeAt(Index);
640
                          // A valid sequence comprises four hexdigits (case-
641
                          // insensitive) that form a single hexadecimal value.
642
                          if (!(charCode >= 48 && charCode <= 57 || charCode >= 97 && charCode <= 102 || charCode >= 65 && charCode <= 70)) {
643
                            // Invalid Unicode escape sequence.
644
                            abort();
645
                          }
646
                        }
647
                        // Revive the escaped character.
648
                        value += fromCharCode("0x" + source.slice(begin, Index));
649
                        break;
650
                      default:
651
                        // Invalid escape sequence.
652
                        abort();
653
                    }
654
                  } else {
655
                    if (charCode == 34) {
656
                      // An unescaped double-quote character marks the end of the
657
                      // string.
658
                      break;
659
                    }
660
                    charCode = source.charCodeAt(Index);
661
                    begin = Index;
662
                    // Optimize for the common case where a string is valid.
663
                    while (charCode >= 32 && charCode != 92 && charCode != 34) {
664
                      charCode = source.charCodeAt(++Index);
665
                    }
666
                    // Append the string as-is.
667
                    value += source.slice(begin, Index);
668
                  }
669
                }
670
                if (source.charCodeAt(Index) == 34) {
671
                  // Advance to the next character and return the revived string.
672
                  Index++;
673
                  return value;
674
                }
675
                // Unterminated string.
676
                abort();
677
              default:
678
                // Parse numbers and literals.
679
                begin = Index;
680
                // Advance past the negative sign, if one is specified.
681
                if (charCode == 45) {
682
                  isSigned = true;
683
                  charCode = source.charCodeAt(++Index);
684
                }
685
                // Parse an integer or floating-point value.
686
                if (charCode >= 48 && charCode <= 57) {
687
                  // Leading zeroes are interpreted as octal literals.
688
                  if (charCode == 48 && ((charCode = source.charCodeAt(Index + 1)), charCode >= 48 && charCode <= 57)) {
689
                    // Illegal octal literal.
690
                    abort();
691
                  }
692
                  isSigned = false;
693
                  // Parse the integer component.
694
                  for (; Index < length && ((charCode = source.charCodeAt(Index)), charCode >= 48 && charCode <= 57); Index++);
695
                  // Floats cannot contain a leading decimal point; however, this
696
                  // case is already accounted for by the parser.
697
                  if (source.charCodeAt(Index) == 46) {
698
                    position = ++Index;
699
                    // Parse the decimal component.
700
                    for (; position < length; position++) {
701
                      charCode = source.charCodeAt(position);
702
                      if (charCode < 48 || charCode > 57) {
703
                        break;
704
                      }
705
                    }
706
                    if (position == Index) {
707
                      // Illegal trailing decimal.
708
                      abort();
709
                    }
710
                    Index = position;
711
                  }
712
                  // Parse exponents. The `e` denoting the exponent is
713
                  // case-insensitive.
714
                  charCode = source.charCodeAt(Index);
715
                  if (charCode == 101 || charCode == 69) {
716
                    charCode = source.charCodeAt(++Index);
717
                    // Skip past the sign following the exponent, if one is
718
                    // specified.
719
                    if (charCode == 43 || charCode == 45) {
720
                      Index++;
721
                    }
722
                    // Parse the exponential component.
723
                    for (position = Index; position < length; position++) {
724
                      charCode = source.charCodeAt(position);
725
                      if (charCode < 48 || charCode > 57) {
726
                        break;
727
                      }
728
                    }
729
                    if (position == Index) {
730
                      // Illegal empty exponent.
731
                      abort();
732
                    }
733
                    Index = position;
734
                  }
735
                  // Coerce the parsed value to a JavaScript number.
736
                  return +source.slice(begin, Index);
737
                }
738
                // A negative sign may only precede numbers.
739
                if (isSigned) {
740
                  abort();
741
                }
742
                // `true`, `false`, and `null` literals.
743
                var temp = source.slice(Index, Index + 4);
744
                if (temp == "true") {
745
                  Index += 4;
746
                  return true;
747
                } else if (temp == "fals" && source.charCodeAt(Index + 4 ) == 101) {
748
                  Index += 5;
749
                  return false;
750
                } else if (temp == "null") {
751
                  Index += 4;
752
                  return null;
753
                }
754
                // Unrecognized token.
755
                abort();
756
            }
757
          }
758
          // Return the sentinel `$` character if the parser has reached the end
759
          // of the source string.
760
          return "$";
761
        };
762
763
        // Internal: Parses a JSON `value` token.
764
        var get = function (value) {
765
          var results, hasMembers;
766
          if (value == "$") {
767
            // Unexpected end of input.
768
            abort();
769
          }
770
          if (typeof value == "string") {
771
            if ((charIndexBuggy ? value.charAt(0) : value[0]) == "@") {
772
              // Remove the sentinel `@` character.
773
              return value.slice(1);
774
            }
775
            // Parse object and array literals.
776
            if (value == "[") {
777
              // Parses a JSON array, returning a new JavaScript array.
778
              results = [];
779
              for (;;) {
780
                value = lex();
781
                // A closing square bracket marks the end of the array literal.
782
                if (value == "]") {
783
                  break;
784
                }
785
                // If the array literal contains elements, the current token
786
                // should be a comma separating the previous element from the
787
                // next.
788
                if (hasMembers) {
789
                  if (value == ",") {
790
                    value = lex();
791
                    if (value == "]") {
792
                      // Unexpected trailing `,` in array literal.
793
                      abort();
794
                    }
795
                  } else {
796
                    // A `,` must separate each array element.
797
                    abort();
798
                  }
799
                } else {
800
                  hasMembers = true;
801
                }
802
                // Elisions and leading commas are not permitted.
803
                if (value == ",") {
804
                  abort();
805
                }
806
                results.push(get(value));
807
              }
808
              return results;
809
            } else if (value == "{") {
810
              // Parses a JSON object, returning a new JavaScript object.
811
              results = {};
812
              for (;;) {
813
                value = lex();
814
                // A closing curly brace marks the end of the object literal.
815
                if (value == "}") {
816
                  break;
817
                }
818
                // If the object literal contains members, the current token
819
                // should be a comma separator.
820
                if (hasMembers) {
821
                  if (value == ",") {
822
                    value = lex();
823
                    if (value == "}") {
824
                      // Unexpected trailing `,` in object literal.
825
                      abort();
826
                    }
827
                  } else {
828
                    // A `,` must separate each object member.
829
                    abort();
830
                  }
831
                } else {
832
                  hasMembers = true;
833
                }
834
                // Leading commas are not permitted, object property names must be
835
                // double-quoted strings, and a `:` must separate each property
836
                // name and value.
837
                if (value == "," || typeof value != "string" || (charIndexBuggy ? value.charAt(0) : value[0]) != "@" || lex() != ":") {
838
                  abort();
839
                }
840
                results[value.slice(1)] = get(lex());
841
              }
842
              return results;
843
            }
844
            // Unexpected token encountered.
845
            abort();
846
          }
847
          return value;
848
        };
849
850
        // Internal: Updates a traversed object member.
851
        var update = function (source, property, callback) {
852
          var element = walk(source, property, callback);
853
          if (element === undefined) {
854
            delete source[property];
855
          } else {
856
            source[property] = element;
857
          }
858
        };
859
860
        // Internal: Recursively traverses a parsed JSON object, invoking the
861
        // `callback` function for each value. This is an implementation of the
862
        // `Walk(holder, name)` operation defined in ES 5.1 section 15.12.2.
863
        var walk = function (source, property, callback) {
864
          var value = source[property], length;
865
          if (typeof value == "object" && value) {
866
            // `forOwn` can't be used to traverse an array in Opera <= 8.54
867
            // because its `Object#hasOwnProperty` implementation returns `false`
868
            // for array indices (e.g., `![1, 2, 3].hasOwnProperty("0")`).
869
            if (getClass.call(value) == arrayClass) {
870
              for (length = value.length; length--;) {
871
                update(getClass, forOwn, value, length, callback);
872
              }
873
            } else {
874
              forOwn(value, function (property) {
875
                update(value, property, callback);
876
              });
877
            }
878
          }
879
          return callback.call(source, property, value);
880
        };
881
882
        // Public: `JSON.parse`. See ES 5.1 section 15.12.2.
883
        exports.parse = function (source, callback) {
884
          var result, value;
885
          Index = 0;
886
          Source = "" + source;
887
          result = get(lex());
888
          // If a JSON string contains multiple tokens, it is invalid.
889
          if (lex() != "$") {
890
            abort();
891
          }
892
          // Reset the parser state.
893
          Index = Source = null;
894
          return callback && getClass.call(callback) == functionClass ? walk((value = {}, value[""] = result, value), "", callback) : result;
895
        };
896
      }
897
    }
898
899
    exports.runInContext = runInContext;
900
    return exports;
901
  }
902
903
  if (freeExports && !isLoader) {
904
    // Export for CommonJS environments.
905
    runInContext(root, freeExports);
906
  } else {
907
    // Export for web browsers and JavaScript engines.
908
    var nativeJSON = root.JSON,
909
        previousJSON = root.JSON3,
910
        isRestored = false;
911
912
    var JSON3 = runInContext(root, (root.JSON3 = {
913
      // Public: Restores the original value of the global `JSON` object and
914
      // returns a reference to the `JSON3` object.
915
      "noConflict": function () {
916
        if (!isRestored) {
917
          isRestored = true;
918
          root.JSON = nativeJSON;
919
          root.JSON3 = previousJSON;
920
          nativeJSON = previousJSON = null;
921
        }
922
        return JSON3;
923
      }
924
    }));
925
926
    root.JSON = {
927
      "parse": JSON3.parse,
928
      "stringify": JSON3.stringify
929
    };
930
  }
931
932
  // Export for asynchronous module loaders.
933
  if (isLoader) {
934
    define(function () {
935
      return JSON3;
936
    });
937
  }
938
}).call(this);