{"version":3,"sources":["ejson/ejson.js","ejson/stringify.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAAA,G;AACA,a;AACA,yC;AACA,G;AACA,W;AACA,e;;;;AAIA,mC;AACA,G;AACA,oB;AACA,2B;AACA,kB;AACA,2E;AACA,uC;AACA,G;;AAEA,G;AACA,qB;AACA,6B;AACA,mJ;AACA,kB;AACA,Y;AACA,G;;AAEA,G;AACA,wB;AACA,6B;AACA,iE;AACA,kB;AACA,Y;AACA,G;;AAEA,G;AACA,kB;AACA,6B;AACA,gI;AACA,kB;AACA,Y;AACA,G;;AAEA,G;AACA,mB;AACA,6B;AACA,oF;AACA,kB;AACA,2D;AACA,Y;AACA,G;;;AAGA,qB;AACA,iE;AACA,+D;AACA,6C;AACA,8B;AACA,4D;AACA,sE;AACA,qD;AACA,oE;AACA,6D;AACA,gB;AACA,oE;AACA,iD;AACA,G;AACA,2C;AACA,kB;AACA,+K;AACA,oM;AACA,G;AACA,0C;AACA,+B;AACA,yD;AACA,8B;AACA,E;;AAEA,iC;AACA,+D;AACA,E;;AAEA,yB;AACA,W;AACA,oC;AACA,sD;AACA,M;AACA,iC;AACA,iC;AACA,M;AACA,iC;AACA,oC;AACA,M;AACA,mC;AACA,iC;AACA,K;AACA,I;AACA,2E;AACA,uB;AACA,oC;AACA,wD;AACA,M;AACA,4B;AACA,iC;AACA,e;AACA,uB;AACA,iB;AACA,gC;AACA,iB;AACA,U;AACA,kB;AACA,6B;AACA,M;AACA,mC;AACA,2B;AACA,K;AACA,I;AACA,a;AACA,oC;AACA,wD;AACA,M;AACA,iC;AACA,2E;AACA,sD;AACA,M;AACA,iC;AACA,2C;AACA,M;AACA,mC;AACA,wC;AACA,K;AACA,I;AACA,yB;AACA,oC;AACA,wD;AACA,M;AACA,iC;AACA,8C;AACA,qB;AACA,O;AACA,4D;AACA,6C;AACA,S;AACA,M;AACA,iC;AACA,sB;AACA,yC;AACA,+C;AACA,S;AACA,+B;AACA,M;AACA,mC;AACA,sB;AACA,iD;AACA,iD;AACA,S;AACA,oB;AACA,K;AACA,I;AACA,a;AACA,oC;AACA,8E;AACA,M;AACA,iC;AACA,sC;AACA,M;AACA,iC;AACA,2D;AACA,iC;AACA,S;AACA,wD;AACA,M;AACA,mC;AACA,+B;AACA,wC;AACA,6E;AACA,4C;AACA,kD;AACA,qC;AACA,S;AACA,K;AACA,G;AACA,E;;AAEA,sC;AACA,e;AACA,4C;AACA,yC;AACA,uC;AACA,E;;;AAGA,sD;AACA,4B;AACA,gD;AACA,0C;AACA,mB;AACA,gB;AACA,4C;AACA,iC;AACA,wB;;AAEA,+B;AACA,8B;AACA,e;;AAEA,4C;AACA,qC;AACA,2D;AACA,2B;AACA,yB;;AAEA,2C;AACA,kB;AACA,yB;AACA,mC;AACA,K;AACA,4D;AACA,+B;AACA,kC;AACA,K;AACA,a;AACA,E;;AAEA,8E;AACA,sE;AACA,yC;AACA,sD;AACA,yC;AACA,sC;AACA,yC;AACA,K;AACA,G;AACA,mB;AACA,E;;AAEA,G;AACA,mF;AACA,kB;AACA,yD;AACA,G;AACA,qC;AACA,wC;AACA,4B;AACA,mB;AACA,iC;AACA,6B;AACA,iC;AACA,G;AACA,c;AACA,E;;AAEA,sD;AACA,uD;AACA,6D;AACA,E;AACA,8B;AACA,kD;AACA,mB;AACA,gB;AACA,8C;AACA,2B;AACA,wB;;AAEA,+B;AACA,8B;AACA,e;;AAEA,qC;AACA,oC;AACA,+C;AACA,8B;AACA,2B;AACA,e;AACA,O;AACA,8D;AACA,iC;AACA,sC;AACA,K;AACA,K;AACA,a;AACA,E;;AAEA,0D;AACA,6D;;AAEA,uE;AACA,sB;AACA,4C;AACA,oD;AACA,0B;AACA,yC;AACA,iE;AACA,a;AACA,0D;AACA,6C;AACA,8C;AACA,gD;AACA,S;AACA,O;AACA,K;AACA,G;AACA,e;AACA,E;;AAEA,G;AACA,0E;AACA,kB;AACA,iE;AACA,G;AACA,uC;AACA,0C;AACA,qD;AACA,6B;AACA,mC;AACA,gB;AACA,U;AACA,mB;AACA,G;AACA,E;;AAEA,G;AACA,0C;;AAEA,kI;AACA,kB;AACA,2C;AACA,4B;AACA,2P;AACA,iG;AACA,G;AACA,4C;AACA,qC;AACA,yD;AACA,oD;AACA,U;AACA,gC;AACA,G;AACA,E;;AAEA,G;AACA,iG;AACA,kB;AACA,6D;AACA,G;AACA,+B;AACA,+B;AACA,+D;AACA,+C;AACA,E;;AAEA,G;AACA,oH;AACA,2C;AACA,kB;AACA,G;AACA,iC;AACA,+E;AACA,sC;AACA,E;;AAEA,G;AACA,2K;AACA,kB;AACA,mB;AACA,mB;AACA,4B;AACA,uP;AACA,G;AACA,yC;AACA,Q;AACA,mE;AACA,c;AACA,gB;AACA,+B;AACA,uF;AACA,4F;AACA,4E;AACA,iB;AACA,wD;AACA,iB;AACA,6C;AACA,uC;AACA,+C;AACA,8B;AACA,mB;AACA,oC;AACA,wB;AACA,qB;AACA,K;AACA,gB;AACA,G;AACA,uC;AACA,gC;AACA,uC;AACA,gC;AACA,2B;AACA,8B;AACA,mB;AACA,8B;AACA,mB;AACA,oC;AACA,6C;AACA,qB;AACA,K;AACA,gB;AACA,G;AACA,oE;AACA,4D;AACA,yB;AACA,4E;AACA,G;AACA,gD;AACA,U;AACA,0B;AACA,mB;AACA,iC;AACA,sB;AACA,O;AACA,U;AACA,sC;AACA,8B;AACA,qB;AACA,O;AACA,2B;AACA,qB;AACA,O;AACA,qD;AACA,qB;AACA,O;AACA,U;AACA,kB;AACA,O;AACA,qC;AACA,U;AACA,U;AACA,wC;AACA,2B;AACA,qB;AACA,O;AACA,gD;AACA,qB;AACA,O;AACA,U;AACA,kB;AACA,O;AACA,kC;AACA,G;AACA,E;;AAEA,G;AACA,wC;AACA,kB;AACA,sC;AACA,G;AACA,4B;AACA,U;AACA,4B;AACA,a;AACA,iB;AACA,4C;AACA,wB;AACA,iC;AACA,8E;AACA,8E;AACA,0B;AACA,a;AACA,0B;AACA,oC;AACA,wC;AACA,oB;AACA,K;AACA,e;AACA,G;AACA,wD;AACA,yC;AACA,+E;AACA,iB;AACA,a;AACA,kC;AACA,iC;AACA,e;AACA,G;AACA,0E;AACA,sC;AACA,qB;AACA,G;AACA,8B;AACA,+B;AACA,wE;AACA,G;AACA,yB;AACA,W;AACA,mC;AACA,kC;AACA,K;AACA,a;AACA,E;;AAEA,G;AACA,0E;AACA,kB;AACA,uE;AACA,G;AACA,uE;AACA,6D;AACA,uE;AACA,qE;AACA,8B;AACA,mC;;;;;;;;;;;;;;;;;;;AC5fA,qE;AACA,E;AACA,c;AACA,gB;AACA,E;AACA,oB;AACA,E;AACA,6D;;AAEA,wB;AACA,gC;AACA,C;;AAEA,wE;;AAEA,uC;;AAEA,sC;AACA,oC;AACA,sC;AACA,a;AACA,gC;AACA,c;AACA,0B;;AAEA,mD;;AAEA,yB;AACA,gB;AACA,wB;AACA,gB;AACA,sE;AACA,oD;AACA,iB;AACA,yB;AACA,+E;AACA,U;AACA,gB;AACA,6E;AACA,kC;AACA,iB;AACA,oB;AACA,K;AACA,mF;AACA,6C;AACA,iB;;AAEA,6B;AACA,mD;;AAEA,kF;AACA,6B;;AAEA,4B;AACA,uC;AACA,mF;AACA,O;;AAEA,mF;AACA,kB;;AAEA,iC;AACA,iB;AACA,+B;AACA,+F;AACA,c;AACA,0C;AACA,O;AACA,e;AACA,K;;;AAGA,qD;AACA,6B;AACA,kB;AACA,yB;AACA,+B;AACA,8D;AACA,c;AACA,gE;AACA,O;AACA,O;;;AAGA,oE;AACA,+B;;AAEA,+B;AACA,e;AACA,6B;AACA,6F;AACA,Y;AACA,wC;AACA,K;AACA,a;AACA,G;AACA,C;;AAEA,wE;;AAEA,uD;AACA,sE;AACA,iD;AACA,sB;AACA,e;AACA,oB;AACA,c;AACA,gC;AACA,0B;AACA,kD;AACA,uB;AACA,8C;AACA,uB;AACA,K;AACA,+B;AACA,G;AACA,qE;AACA,E","file":"/packages/ejson.js","sourcesContent":["/**\n * @namespace\n * @summary Namespace for EJSON functions\n */\nEJSON = {};\nEJSONTest = {};\n\n\n\n// Custom type interface definition\n/**\n * @class CustomType\n * @instanceName customType\n * @memberOf EJSON\n * @summary The interface that a class must satisfy to be able to become an\n * EJSON custom type via EJSON.addType.\n */\n\n/**\n * @function typeName\n * @memberOf EJSON.CustomType\n * @summary Return the tag used to identify this type.  This must match the tag used to register this type with [`EJSON.addType`](#ejson_add_type).\n * @locus Anywhere\n * @instance\n */\n\n/**\n * @function toJSONValue\n * @memberOf EJSON.CustomType\n * @summary Serialize this instance into a JSON-compatible value.\n * @locus Anywhere\n * @instance\n */\n\n/**\n * @function clone\n * @memberOf EJSON.CustomType\n * @summary Return a value `r` such that `this.equals(r)` is true, and modifications to `r` do not affect `this` and vice versa.\n * @locus Anywhere\n * @instance\n */\n\n/**\n * @function equals\n * @memberOf EJSON.CustomType\n * @summary Return `true` if `other` has a value equal to `this`; `false` otherwise.\n * @locus Anywhere\n * @param {Object} other Another object to compare this to.\n * @instance\n */\n\n\nvar customTypes = {};\n// Add a custom type, using a method of your choice to get to and\n// from a basic JSON-able representation.  The factory argument\n// is a function of JSON-able --> your object\n// The type you add must have:\n// - A toJSONValue() method, so that Meteor can serialize it\n// - a typeName() method, to show how to look it up in our type table.\n// It is okay if these methods are monkey-patched on.\n// EJSON.clone will use toJSONValue and the given factory to produce\n// a clone, but you may specify a method clone() that will be\n// used instead.\n// Similarly, EJSON.equals will use toJSONValue to make comparisons,\n// but you may provide a method equals() instead.\n/**\n * @summary Add a custom datatype to EJSON.\n * @locus Anywhere\n * @param {String} name A tag for your custom type; must be unique among custom data types defined in your project, and must match the result of your type's `typeName` method.\n * @param {Function} factory A function that deserializes a JSON-compatible value into an instance of your type.  This should match the serialization performed by your type's `toJSONValue` method.\n */\nEJSON.addType = function (name, factory) {\n  if (_.has(customTypes, name))\n    throw new Error(\"Type \" + name + \" already present\");\n  customTypes[name] = factory;\n};\n\nvar isInfOrNan = function (obj) {\n  return _.isNaN(obj) || obj === Infinity || obj === -Infinity;\n};\n\nvar builtinConverters = [\n  { // Date\n    matchJSONValue: function (obj) {\n      return _.has(obj, '$date') && _.size(obj) === 1;\n    },\n    matchObject: function (obj) {\n      return obj instanceof Date;\n    },\n    toJSONValue: function (obj) {\n      return {$date: obj.getTime()};\n    },\n    fromJSONValue: function (obj) {\n      return new Date(obj.$date);\n    }\n  },\n  { // NaN, Inf, -Inf. (These are the only objects with typeof !== 'object'\n    // which we match.)\n    matchJSONValue: function (obj) {\n      return _.has(obj, '$InfNaN') && _.size(obj) === 1;\n    },\n    matchObject: isInfOrNan,\n    toJSONValue: function (obj) {\n      var sign;\n      if (_.isNaN(obj))\n        sign = 0;\n      else if (obj === Infinity)\n        sign = 1;\n      else\n        sign = -1;\n      return {$InfNaN: sign};\n    },\n    fromJSONValue: function (obj) {\n      return obj.$InfNaN/0;\n    }\n  },\n  { // Binary\n    matchJSONValue: function (obj) {\n      return _.has(obj, '$binary') && _.size(obj) === 1;\n    },\n    matchObject: function (obj) {\n      return typeof Uint8Array !== 'undefined' && obj instanceof Uint8Array\n        || (obj && _.has(obj, '$Uint8ArrayPolyfill'));\n    },\n    toJSONValue: function (obj) {\n      return {$binary: Base64.encode(obj)};\n    },\n    fromJSONValue: function (obj) {\n      return Base64.decode(obj.$binary);\n    }\n  },\n  { // Escaping one level\n    matchJSONValue: function (obj) {\n      return _.has(obj, '$escape') && _.size(obj) === 1;\n    },\n    matchObject: function (obj) {\n      if (_.isEmpty(obj) || _.size(obj) > 2) {\n        return false;\n      }\n      return _.any(builtinConverters, function (converter) {\n        return converter.matchJSONValue(obj);\n      });\n    },\n    toJSONValue: function (obj) {\n      var newObj = {};\n      _.each(obj, function (value, key) {\n        newObj[key] = EJSON.toJSONValue(value);\n      });\n      return {$escape: newObj};\n    },\n    fromJSONValue: function (obj) {\n      var newObj = {};\n      _.each(obj.$escape, function (value, key) {\n        newObj[key] = EJSON.fromJSONValue(value);\n      });\n      return newObj;\n    }\n  },\n  { // Custom\n    matchJSONValue: function (obj) {\n      return _.has(obj, '$type') && _.has(obj, '$value') && _.size(obj) === 2;\n    },\n    matchObject: function (obj) {\n      return EJSON._isCustomType(obj);\n    },\n    toJSONValue: function (obj) {\n      var jsonValue = Meteor._noYieldsAllowed(function () {\n        return obj.toJSONValue();\n      });\n      return {$type: obj.typeName(), $value: jsonValue};\n    },\n    fromJSONValue: function (obj) {\n      var typeName = obj.$type;\n      if (!_.has(customTypes, typeName))\n        throw new Error(\"Custom EJSON type \" + typeName + \" is not defined\");\n      var converter = customTypes[typeName];\n      return Meteor._noYieldsAllowed(function () {\n        return converter(obj.$value);\n      });\n    }\n  }\n];\n\nEJSON._isCustomType = function (obj) {\n  return obj &&\n    typeof obj.toJSONValue === 'function' &&\n    typeof obj.typeName === 'function' &&\n    _.has(customTypes, obj.typeName());\n};\n\n\n// for both arrays and objects, in-place modification.\nvar adjustTypesToJSONValue =\nEJSON._adjustTypesToJSONValue = function (obj) {\n  // Is it an atom that we need to adjust?\n  if (obj === null)\n    return null;\n  var maybeChanged = toJSONValueHelper(obj);\n  if (maybeChanged !== undefined)\n    return maybeChanged;\n\n  // Other atoms are unchanged.\n  if (typeof obj !== 'object')\n    return obj;\n\n  // Iterate over array or object structure.\n  _.each(obj, function (value, key) {\n    if (typeof value !== 'object' && value !== undefined &&\n        !isInfOrNan(value))\n      return; // continue\n\n    var changed = toJSONValueHelper(value);\n    if (changed) {\n      obj[key] = changed;\n      return; // on to the next key\n    }\n    // if we get here, value is an object but not adjustable\n    // at this level.  recurse.\n    adjustTypesToJSONValue(value);\n  });\n  return obj;\n};\n\n// Either return the JSON-compatible version of the argument, or undefined (if\n// the item isn't itself replaceable, but maybe some fields in it are)\nvar toJSONValueHelper = function (item) {\n  for (var i = 0; i < builtinConverters.length; i++) {\n    var converter = builtinConverters[i];\n    if (converter.matchObject(item)) {\n      return converter.toJSONValue(item);\n    }\n  }\n  return undefined;\n};\n\n/**\n * @summary Serialize an EJSON-compatible value into its plain JSON representation.\n * @locus Anywhere\n * @param {EJSON} val A value to serialize to plain JSON.\n */\nEJSON.toJSONValue = function (item) {\n  var changed = toJSONValueHelper(item);\n  if (changed !== undefined)\n    return changed;\n  if (typeof item === 'object') {\n    item = EJSON.clone(item);\n    adjustTypesToJSONValue(item);\n  }\n  return item;\n};\n\n// for both arrays and objects. Tries its best to just\n// use the object you hand it, but may return something\n// different if the object you hand it itself needs changing.\n//\nvar adjustTypesFromJSONValue =\nEJSON._adjustTypesFromJSONValue = function (obj) {\n  if (obj === null)\n    return null;\n  var maybeChanged = fromJSONValueHelper(obj);\n  if (maybeChanged !== obj)\n    return maybeChanged;\n\n  // Other atoms are unchanged.\n  if (typeof obj !== 'object')\n    return obj;\n\n  _.each(obj, function (value, key) {\n    if (typeof value === 'object') {\n      var changed = fromJSONValueHelper(value);\n      if (value !== changed) {\n        obj[key] = changed;\n        return;\n      }\n      // if we get here, value is an object but not adjustable\n      // at this level.  recurse.\n      adjustTypesFromJSONValue(value);\n    }\n  });\n  return obj;\n};\n\n// Either return the argument changed to have the non-json\n// rep of itself (the Object version) or the argument itself.\n\n// DOES NOT RECURSE.  For actually getting the fully-changed value, use\n// EJSON.fromJSONValue\nvar fromJSONValueHelper = function (value) {\n  if (typeof value === 'object' && value !== null) {\n    if (_.size(value) <= 2\n        && _.all(value, function (v, k) {\n          return typeof k === 'string' && k.substr(0, 1) === '$';\n        })) {\n      for (var i = 0; i < builtinConverters.length; i++) {\n        var converter = builtinConverters[i];\n        if (converter.matchJSONValue(value)) {\n          return converter.fromJSONValue(value);\n        }\n      }\n    }\n  }\n  return value;\n};\n\n/**\n * @summary Deserialize an EJSON value from its plain JSON representation.\n * @locus Anywhere\n * @param {JSONCompatible} val A value to deserialize into EJSON.\n */\nEJSON.fromJSONValue = function (item) {\n  var changed = fromJSONValueHelper(item);\n  if (changed === item && typeof item === 'object') {\n    item = EJSON.clone(item);\n    adjustTypesFromJSONValue(item);\n    return item;\n  } else {\n    return changed;\n  }\n};\n\n/**\n * @summary Serialize a value to a string.\n\nFor EJSON values, the serialization fully represents the value. For non-EJSON values, serializes the same way as `JSON.stringify`.\n * @locus Anywhere\n * @param {EJSON} val A value to stringify.\n * @param {Object} [options]\n * @param {Boolean | Integer | String} options.indent Indents objects and arrays for easy readability.  When `true`, indents by 2 spaces; when an integer, indents by that number of spaces; and when a string, uses the string as the indentation pattern.\n * @param {Boolean} options.canonical When `true`, stringifies keys in an object in sorted order.\n */\nEJSON.stringify = function (item, options) {\n  var json = EJSON.toJSONValue(item);\n  if (options && (options.canonical || options.indent)) {\n    return EJSON._canonicalStringify(json, options);\n  } else {\n    return JSON.stringify(json);\n  }\n};\n\n/**\n * @summary Parse a string into an EJSON value. Throws an error if the string is not valid EJSON.\n * @locus Anywhere\n * @param {String} str A string to parse into an EJSON value.\n */\nEJSON.parse = function (item) {\n  if (typeof item !== 'string')\n    throw new Error(\"EJSON.parse argument should be a string\");\n  return EJSON.fromJSONValue(JSON.parse(item));\n};\n\n/**\n * @summary Returns true if `x` is a buffer of binary data, as returned from [`EJSON.newBinary`](#ejson_new_binary).\n * @param {Object} x The variable to check.\n * @locus Anywhere\n */\nEJSON.isBinary = function (obj) {\n  return !!((typeof Uint8Array !== 'undefined' && obj instanceof Uint8Array) ||\n    (obj && obj.$Uint8ArrayPolyfill));\n};\n\n/**\n * @summary Return true if `a` and `b` are equal to each other.  Return false otherwise.  Uses the `equals` method on `a` if present, otherwise performs a deep comparison.\n * @locus Anywhere\n * @param {EJSON} a\n * @param {EJSON} b\n * @param {Object} [options]\n * @param {Boolean} options.keyOrderSensitive Compare in key sensitive order, if supported by the JavaScript implementation.  For example, `{a: 1, b: 2}` is equal to `{b: 2, a: 1}` only when `keyOrderSensitive` is `false`.  The default is `false`.\n */\nEJSON.equals = function (a, b, options) {\n  var i;\n  var keyOrderSensitive = !!(options && options.keyOrderSensitive);\n  if (a === b)\n    return true;\n  if (_.isNaN(a) && _.isNaN(b))\n    return true; // This differs from the IEEE spec for NaN equality, b/c we don't want\n                 // anything ever with a NaN to be poisoned from becoming equal to anything.\n  if (!a || !b) // if either one is falsy, they'd have to be === to be equal\n    return false;\n  if (!(typeof a === 'object' && typeof b === 'object'))\n    return false;\n  if (a instanceof Date && b instanceof Date)\n    return a.valueOf() === b.valueOf();\n  if (EJSON.isBinary(a) && EJSON.isBinary(b)) {\n    if (a.length !== b.length)\n      return false;\n    for (i = 0; i < a.length; i++) {\n      if (a[i] !== b[i])\n        return false;\n    }\n    return true;\n  }\n  if (typeof (a.equals) === 'function')\n    return a.equals(b, options);\n  if (typeof (b.equals) === 'function')\n    return b.equals(a, options);\n  if (a instanceof Array) {\n    if (!(b instanceof Array))\n      return false;\n    if (a.length !== b.length)\n      return false;\n    for (i = 0; i < a.length; i++) {\n      if (!EJSON.equals(a[i], b[i], options))\n        return false;\n    }\n    return true;\n  }\n  // fallback for custom types that don't implement their own equals\n  switch (EJSON._isCustomType(a) + EJSON._isCustomType(b)) {\n    case 1: return false;\n    case 2: return EJSON.equals(EJSON.toJSONValue(a), EJSON.toJSONValue(b));\n  }\n  // fall back to structural equality of objects\n  var ret;\n  if (keyOrderSensitive) {\n    var bKeys = [];\n    _.each(b, function (val, x) {\n        bKeys.push(x);\n    });\n    i = 0;\n    ret = _.all(a, function (val, x) {\n      if (i >= bKeys.length) {\n        return false;\n      }\n      if (x !== bKeys[i]) {\n        return false;\n      }\n      if (!EJSON.equals(val, b[bKeys[i]], options)) {\n        return false;\n      }\n      i++;\n      return true;\n    });\n    return ret && i === bKeys.length;\n  } else {\n    i = 0;\n    ret = _.all(a, function (val, key) {\n      if (!_.has(b, key)) {\n        return false;\n      }\n      if (!EJSON.equals(val, b[key], options)) {\n        return false;\n      }\n      i++;\n      return true;\n    });\n    return ret && _.size(b) === i;\n  }\n};\n\n/**\n * @summary Return a deep copy of `val`.\n * @locus Anywhere\n * @param {EJSON} val A value to copy.\n */\nEJSON.clone = function (v) {\n  var ret;\n  if (typeof v !== \"object\")\n    return v;\n  if (v === null)\n    return null; // null has typeof \"object\"\n  if (v instanceof Date)\n    return new Date(v.getTime());\n  // RegExps are not really EJSON elements (eg we don't define a serialization\n  // for them), but they're immutable anyway, so we can support them in clone.\n  if (v instanceof RegExp)\n    return v;\n  if (EJSON.isBinary(v)) {\n    ret = EJSON.newBinary(v.length);\n    for (var i = 0; i < v.length; i++) {\n      ret[i] = v[i];\n    }\n    return ret;\n  }\n  // XXX: Use something better than underscore's isArray\n  if (_.isArray(v) || _.isArguments(v)) {\n    // For some reason, _.map doesn't work in this context on Opera (weird test\n    // failures).\n    ret = [];\n    for (i = 0; i < v.length; i++)\n      ret[i] = EJSON.clone(v[i]);\n    return ret;\n  }\n  // handle general user-defined typed Objects if they have a clone method\n  if (typeof v.clone === 'function') {\n    return v.clone();\n  }\n  // handle other custom types\n  if (EJSON._isCustomType(v)) {\n    return EJSON.fromJSONValue(EJSON.clone(EJSON.toJSONValue(v)), true);\n  }\n  // handle other objects\n  ret = {};\n  _.each(v, function (value, key) {\n    ret[key] = EJSON.clone(value);\n  });\n  return ret;\n};\n\n/**\n * @summary Allocate a new buffer of binary data that EJSON can serialize.\n * @locus Anywhere\n * @param {Number} size The number of bytes of binary data to allocate.\n */\n// EJSON.newBinary is the public documented API for this functionality,\n// but the implementation is in the 'base64' package to avoid\n// introducing a circular dependency. (If the implementation were here,\n// then 'base64' would have to use EJSON.newBinary, and 'ejson' would\n// also have to use 'base64'.)\nEJSON.newBinary = Base64.newBinary;\n","// Based on json2.js from https://github.com/douglascrockford/JSON-js\n//\n//    json2.js\n//    2012-10-08\n//\n//    Public Domain.\n//\n//    NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.\n\nfunction quote(string) {\n  return JSON.stringify(string);\n}\n\nvar str = function (key, holder, singleIndent, outerIndent, canonical) {\n\n  // Produce a string from holder[key].\n\n  var i;          // The loop counter.\n  var k;          // The member key.\n  var v;          // The member value.\n  var length;\n  var innerIndent = outerIndent;\n  var partial;\n  var value = holder[key];\n\n  // What happens next depends on the value's type.\n\n  switch (typeof value) {\n  case 'string':\n    return quote(value);\n  case 'number':\n    // JSON numbers must be finite. Encode non-finite numbers as null.\n    return isFinite(value) ? String(value) : 'null';\n  case 'boolean':\n    return String(value);\n  // If the type is 'object', we might be dealing with an object or an array or\n  // null.\n  case 'object':\n    // Due to a specification blunder in ECMAScript, typeof null is 'object',\n    // so watch out for that case.\n    if (!value) {\n      return 'null';\n    }\n    // Make an array to hold the partial results of stringifying this object value.\n    innerIndent = outerIndent + singleIndent;\n    partial = [];\n\n    // Is the value an array?\n    if (_.isArray(value) || _.isArguments(value)) {\n\n      // The value is an array. Stringify every element. Use null as a placeholder\n      // for non-JSON values.\n\n      length = value.length;\n      for (i = 0; i < length; i += 1) {\n        partial[i] = str(i, value, singleIndent, innerIndent, canonical) || 'null';\n      }\n\n      // Join all of the elements together, separated with commas, and wrap them in\n      // brackets.\n\n      if (partial.length === 0) {\n        v = '[]';\n      } else if (innerIndent) {\n        v = '[\\n' + innerIndent + partial.join(',\\n' + innerIndent) + '\\n' + outerIndent + ']';\n      } else {\n        v = '[' + partial.join(',') + ']';\n      }\n      return v;\n    }\n\n\n    // Iterate through all of the keys in the object.\n    var keys = _.keys(value);\n    if (canonical)\n      keys = keys.sort();\n    _.each(keys, function (k) {\n      v = str(k, value, singleIndent, innerIndent, canonical);\n      if (v) {\n        partial.push(quote(k) + (innerIndent ? ': ' : ':') + v);\n      }\n    });\n\n\n    // Join all of the member texts together, separated with commas,\n    // and wrap them in braces.\n\n    if (partial.length === 0) {\n      v = '{}';\n    } else if (innerIndent) {\n      v = '{\\n' + innerIndent + partial.join(',\\n' + innerIndent) + '\\n' + outerIndent + '}';\n    } else {\n      v = '{' + partial.join(',') + '}';\n    }\n    return v;\n  }\n}\n\n// If the JSON object does not yet have a stringify method, give it one.\n\nEJSON._canonicalStringify = function (value, options) {\n  // Make a fake root object containing our value under the key of ''.\n  // Return the result of stringifying the value.\n  options = _.extend({\n    indent: \"\",\n    canonical: false\n  }, options);\n  if (options.indent === true) {\n    options.indent = \"  \";\n  } else if (typeof options.indent === 'number') {\n    var newIndent = \"\";\n    for (var i = 0; i < options.indent; i++) {\n      newIndent += ' ';\n    }\n    options.indent = newIndent;\n  }\n  return str('', {'': value}, options.indent, \"\", options.canonical);\n};\n"]}