//////////////////////////////////////////////////////////////////////////
//                                                                      //
// This is a generated file. You can view the original                  //
// source in your browser if your browser supports source maps.         //
//                                                                      //
// If you are using Chrome, open the Developer Tools and click the gear //
// icon in its lower right corner. In the General Settings panel, turn  //
// on 'Enable source maps'.                                             //
//                                                                      //
// If you are using Firefox 23, go to `about:config` and set the        //
// `devtools.debugger.source-maps-enabled` preference to true.          //
// (The preference should be on by default in Firefox 24; versions      //
// older than 23 do not support source maps.)                           //
//                                                                      //
//////////////////////////////////////////////////////////////////////////


(function () {

/* Imports */
var Meteor = Package.meteor.Meteor;
var _ = Package.underscore._;
var EJSON = Package.ejson.EJSON;

/* Package-scope variables */
var check, Match;

(function () {

///////////////////////////////////////////////////////////////////////////////////
//                                                                               //
// packages/check/match.js                                                       //
//                                                                               //
///////////////////////////////////////////////////////////////////////////////////
                                                                                 //
// XXX docs                                                                      // 1
                                                                                 // 2
// Things we explicitly do NOT support:                                          // 3
//    - heterogenous arrays                                                      // 4
                                                                                 // 5
var currentArgumentChecker = new Meteor.EnvironmentVariable;                     // 6
                                                                                 // 7
/**                                                                              // 8
 * @summary Check that a value matches a [pattern](#matchpatterns).              // 9
 * If the value does not match the pattern, throw a `Match.Error`.               // 10
 *                                                                               // 11
 * Particularly useful to assert that arguments to a function have the right     // 12
 * types and structure.                                                          // 13
 * @locus Anywhere                                                               // 14
 * @param {Any} value The value to check                                         // 15
 * @param {MatchPattern} pattern The pattern to match                            // 16
 * `value` against                                                               // 17
 */                                                                              // 18
check = function (value, pattern) {                                              // 19
  // Record that check got called, if somebody cared.                            // 20
  //                                                                             // 21
  // We use getOrNullIfOutsideFiber so that it's OK to call check()              // 22
  // from non-Fiber server contexts; the downside is that if you forget to       // 23
  // bindEnvironment on some random callback in your method/publisher,           // 24
  // it might not find the argumentChecker and you'll get an error about         // 25
  // not checking an argument that it looks like you're checking (instead        // 26
  // of just getting a "Node code must run in a Fiber" error).                   // 27
  var argChecker = currentArgumentChecker.getOrNullIfOutsideFiber();             // 28
  if (argChecker)                                                                // 29
    argChecker.checking(value);                                                  // 30
  try {                                                                          // 31
    checkSubtree(value, pattern);                                                // 32
  } catch (err) {                                                                // 33
    if ((err instanceof Match.Error) && err.path)                                // 34
      err.message += " in field " + err.path;                                    // 35
    throw err;                                                                   // 36
  }                                                                              // 37
};                                                                               // 38
                                                                                 // 39
/**                                                                              // 40
 * @namespace Match                                                              // 41
 * @summary The namespace for all Match types and methods.                       // 42
 */                                                                              // 43
Match = {                                                                        // 44
  Optional: function (pattern) {                                                 // 45
    return new Optional(pattern);                                                // 46
  },                                                                             // 47
  OneOf: function (/*arguments*/) {                                              // 48
    return new OneOf(_.toArray(arguments));                                      // 49
  },                                                                             // 50
  Any: ['__any__'],                                                              // 51
  Where: function (condition) {                                                  // 52
    return new Where(condition);                                                 // 53
  },                                                                             // 54
  ObjectIncluding: function (pattern) {                                          // 55
    return new ObjectIncluding(pattern);                                         // 56
  },                                                                             // 57
  ObjectWithValues: function (pattern) {                                         // 58
    return new ObjectWithValues(pattern);                                        // 59
  },                                                                             // 60
  // Matches only signed 32-bit integers                                         // 61
  Integer: ['__integer__'],                                                      // 62
                                                                                 // 63
  // XXX matchers should know how to describe themselves for errors              // 64
  Error: Meteor.makeErrorType("Match.Error", function (msg) {                    // 65
    this.message = "Match error: " + msg;                                        // 66
    // The path of the value that failed to match. Initially empty, this gets    // 67
    // populated by catching and rethrowing the exception as it goes back up the // 68
    // stack.                                                                    // 69
    // E.g.: "vals[3].entity.created"                                            // 70
    this.path = "";                                                              // 71
    // If this gets sent over DDP, don't give full internal details but at least // 72
    // provide something better than 500 Internal server error.                  // 73
    this.sanitizedError = new Meteor.Error(400, "Match failed");                 // 74
  }),                                                                            // 75
                                                                                 // 76
  // Tests to see if value matches pattern. Unlike check, it merely returns true // 77
  // or false (unless an error other than Match.Error was thrown). It does not   // 78
  // interact with _failIfArgumentsAreNotAllChecked.                             // 79
  // XXX maybe also implement a Match.match which returns more information about // 80
  //     failures but without using exception handling or doing what check()     // 81
  //     does with _failIfArgumentsAreNotAllChecked and Meteor.Error conversion  // 82
                                                                                 // 83
  /**                                                                            // 84
   * @summary Returns true if the value matches the pattern.                     // 85
   * @locus Anywhere                                                             // 86
   * @param {Any} value The value to check                                       // 87
   * @param {MatchPattern} pattern The pattern to match `value` against          // 88
   */                                                                            // 89
  test: function (value, pattern) {                                              // 90
    try {                                                                        // 91
      checkSubtree(value, pattern);                                              // 92
      return true;                                                               // 93
    } catch (e) {                                                                // 94
      if (e instanceof Match.Error)                                              // 95
        return false;                                                            // 96
      // Rethrow other errors.                                                   // 97
      throw e;                                                                   // 98
    }                                                                            // 99
  },                                                                             // 100
                                                                                 // 101
  // Runs `f.apply(context, args)`. If check() is not called on every element of // 102
  // `args` (either directly or in the first level of an array), throws an error // 103
  // (using `description` in the message).                                       // 104
  //                                                                             // 105
  _failIfArgumentsAreNotAllChecked: function (f, context, args, description) {   // 106
    var argChecker = new ArgumentChecker(args, description);                     // 107
    var result = currentArgumentChecker.withValue(argChecker, function () {      // 108
      return f.apply(context, args);                                             // 109
    });                                                                          // 110
    // If f didn't itself throw, make sure it checked all of its arguments.      // 111
    argChecker.throwUnlessAllArgumentsHaveBeenChecked();                         // 112
    return result;                                                               // 113
  }                                                                              // 114
};                                                                               // 115
                                                                                 // 116
var Optional = function (pattern) {                                              // 117
  this.pattern = pattern;                                                        // 118
};                                                                               // 119
                                                                                 // 120
var OneOf = function (choices) {                                                 // 121
  if (_.isEmpty(choices))                                                        // 122
    throw new Error("Must provide at least one choice to Match.OneOf");          // 123
  this.choices = choices;                                                        // 124
};                                                                               // 125
                                                                                 // 126
var Where = function (condition) {                                               // 127
  this.condition = condition;                                                    // 128
};                                                                               // 129
                                                                                 // 130
var ObjectIncluding = function (pattern) {                                       // 131
  this.pattern = pattern;                                                        // 132
};                                                                               // 133
                                                                                 // 134
var ObjectWithValues = function (pattern) {                                      // 135
  this.pattern = pattern;                                                        // 136
};                                                                               // 137
                                                                                 // 138
var typeofChecks = [                                                             // 139
  [String, "string"],                                                            // 140
  [Number, "number"],                                                            // 141
  [Boolean, "boolean"],                                                          // 142
  // While we don't allow undefined in EJSON, this is good for optional          // 143
  // arguments with OneOf.                                                       // 144
  [undefined, "undefined"]                                                       // 145
];                                                                               // 146
                                                                                 // 147
var checkSubtree = function (value, pattern) {                                   // 148
  // Match anything!                                                             // 149
  if (pattern === Match.Any)                                                     // 150
    return;                                                                      // 151
                                                                                 // 152
  // Basic atomic types.                                                         // 153
  // Do not match boxed objects (e.g. String, Boolean)                           // 154
  for (var i = 0; i < typeofChecks.length; ++i) {                                // 155
    if (pattern === typeofChecks[i][0]) {                                        // 156
      if (typeof value === typeofChecks[i][1])                                   // 157
        return;                                                                  // 158
      throw new Match.Error("Expected " + typeofChecks[i][1] + ", got " +        // 159
                            typeof value);                                       // 160
    }                                                                            // 161
  }                                                                              // 162
  if (pattern === null) {                                                        // 163
    if (value === null)                                                          // 164
      return;                                                                    // 165
    throw new Match.Error("Expected null, got " + EJSON.stringify(value));       // 166
  }                                                                              // 167
                                                                                 // 168
  // Strings and numbers match literally.  Goes well with Match.OneOf.           // 169
  if (typeof pattern === "string" || typeof pattern === "number") {              // 170
    if (value === pattern)                                                       // 171
      return;                                                                    // 172
    throw new Match.Error("Expected " + pattern + ", got " +                     // 173
                          EJSON.stringify(value));                               // 174
  }                                                                              // 175
                                                                                 // 176
  // Match.Integer is special type encoded with array                            // 177
  if (pattern === Match.Integer) {                                               // 178
    // There is no consistent and reliable way to check if variable is a 64-bit  // 179
    // integer. One of the popular solutions is to get reminder of division by 1 // 180
    // but this method fails on really large floats with big precision.          // 181
    // E.g.: 1.348192308491824e+23 % 1 === 0 in V8                               // 182
    // Bitwise operators work consistantly but always cast variable to 32-bit    // 183
    // signed integer according to JavaScript specs.                             // 184
    if (typeof value === "number" && (value | 0) === value)                      // 185
      return                                                                     // 186
    throw new Match.Error("Expected Integer, got "                               // 187
                + (value instanceof Object ? EJSON.stringify(value) : value));   // 188
  }                                                                              // 189
                                                                                 // 190
  // "Object" is shorthand for Match.ObjectIncluding({});                        // 191
  if (pattern === Object)                                                        // 192
    pattern = Match.ObjectIncluding({});                                         // 193
                                                                                 // 194
  // Array (checked AFTER Any, which is implemented as an Array).                // 195
  if (pattern instanceof Array) {                                                // 196
    if (pattern.length !== 1)                                                    // 197
      throw Error("Bad pattern: arrays must have one type element" +             // 198
                  EJSON.stringify(pattern));                                     // 199
    if (!_.isArray(value) && !_.isArguments(value)) {                            // 200
      throw new Match.Error("Expected array, got " + EJSON.stringify(value));    // 201
    }                                                                            // 202
                                                                                 // 203
    _.each(value, function (valueElement, index) {                               // 204
      try {                                                                      // 205
        checkSubtree(valueElement, pattern[0]);                                  // 206
      } catch (err) {                                                            // 207
        if (err instanceof Match.Error) {                                        // 208
          err.path = _prependPath(index, err.path);                              // 209
        }                                                                        // 210
        throw err;                                                               // 211
      }                                                                          // 212
    });                                                                          // 213
    return;                                                                      // 214
  }                                                                              // 215
                                                                                 // 216
  // Arbitrary validation checks. The condition can return false or throw a      // 217
  // Match.Error (ie, it can internally use check()) to fail.                    // 218
  if (pattern instanceof Where) {                                                // 219
    if (pattern.condition(value))                                                // 220
      return;                                                                    // 221
    // XXX this error is terrible                                                // 222
    throw new Match.Error("Failed Match.Where validation");                      // 223
  }                                                                              // 224
                                                                                 // 225
                                                                                 // 226
  if (pattern instanceof Optional)                                               // 227
    pattern = Match.OneOf(undefined, pattern.pattern);                           // 228
                                                                                 // 229
  if (pattern instanceof OneOf) {                                                // 230
    for (var i = 0; i < pattern.choices.length; ++i) {                           // 231
      try {                                                                      // 232
        checkSubtree(value, pattern.choices[i]);                                 // 233
        // No error? Yay, return.                                                // 234
        return;                                                                  // 235
      } catch (err) {                                                            // 236
        // Other errors should be thrown. Match errors just mean try another     // 237
        // choice.                                                               // 238
        if (!(err instanceof Match.Error))                                       // 239
          throw err;                                                             // 240
      }                                                                          // 241
    }                                                                            // 242
    // XXX this error is terrible                                                // 243
    throw new Match.Error("Failed Match.OneOf or Match.Optional validation");    // 244
  }                                                                              // 245
                                                                                 // 246
  // A function that isn't something we special-case is assumed to be a          // 247
  // constructor.                                                                // 248
  if (pattern instanceof Function) {                                             // 249
    if (value instanceof pattern)                                                // 250
      return;                                                                    // 251
    throw new Match.Error("Expected " + (pattern.name ||                         // 252
                                         "particular constructor"));             // 253
  }                                                                              // 254
                                                                                 // 255
  var unknownKeysAllowed = false;                                                // 256
  var unknownKeyPattern;                                                         // 257
  if (pattern instanceof ObjectIncluding) {                                      // 258
    unknownKeysAllowed = true;                                                   // 259
    pattern = pattern.pattern;                                                   // 260
  }                                                                              // 261
  if (pattern instanceof ObjectWithValues) {                                     // 262
    unknownKeysAllowed = true;                                                   // 263
    unknownKeyPattern = [pattern.pattern];                                       // 264
    pattern = {};  // no required keys                                           // 265
  }                                                                              // 266
                                                                                 // 267
  if (typeof pattern !== "object")                                               // 268
    throw Error("Bad pattern: unknown pattern type");                            // 269
                                                                                 // 270
  // An object, with required and optional keys. Note that this does NOT do      // 271
  // structural matches against objects of special types that happen to match    // 272
  // the pattern: this really needs to be a plain old {Object}!                  // 273
  if (typeof value !== 'object')                                                 // 274
    throw new Match.Error("Expected object, got " + typeof value);               // 275
  if (value === null)                                                            // 276
    throw new Match.Error("Expected object, got null");                          // 277
  if (value.constructor !== Object)                                              // 278
    throw new Match.Error("Expected plain object");                              // 279
                                                                                 // 280
  var requiredPatterns = {};                                                     // 281
  var optionalPatterns = {};                                                     // 282
  _.each(pattern, function (subPattern, key) {                                   // 283
    if (subPattern instanceof Optional)                                          // 284
      optionalPatterns[key] = subPattern.pattern;                                // 285
    else                                                                         // 286
      requiredPatterns[key] = subPattern;                                        // 287
  });                                                                            // 288
                                                                                 // 289
  _.each(value, function (subValue, key) {                                       // 290
    try {                                                                        // 291
      if (_.has(requiredPatterns, key)) {                                        // 292
        checkSubtree(subValue, requiredPatterns[key]);                           // 293
        delete requiredPatterns[key];                                            // 294
      } else if (_.has(optionalPatterns, key)) {                                 // 295
        checkSubtree(subValue, optionalPatterns[key]);                           // 296
      } else {                                                                   // 297
        if (!unknownKeysAllowed)                                                 // 298
          throw new Match.Error("Unknown key");                                  // 299
        if (unknownKeyPattern) {                                                 // 300
          checkSubtree(subValue, unknownKeyPattern[0]);                          // 301
        }                                                                        // 302
      }                                                                          // 303
    } catch (err) {                                                              // 304
      if (err instanceof Match.Error)                                            // 305
        err.path = _prependPath(key, err.path);                                  // 306
      throw err;                                                                 // 307
    }                                                                            // 308
  });                                                                            // 309
                                                                                 // 310
  _.each(requiredPatterns, function (subPattern, key) {                          // 311
    throw new Match.Error("Missing key '" + key + "'");                          // 312
  });                                                                            // 313
};                                                                               // 314
                                                                                 // 315
var ArgumentChecker = function (args, description) {                             // 316
  var self = this;                                                               // 317
  // Make a SHALLOW copy of the arguments. (We'll be doing identity checks       // 318
  // against its contents.)                                                      // 319
  self.args = _.clone(args);                                                     // 320
  // Since the common case will be to check arguments in order, and we splice    // 321
  // out arguments when we check them, make it so we splice out from the end     // 322
  // rather than the beginning.                                                  // 323
  self.args.reverse();                                                           // 324
  self.description = description;                                                // 325
};                                                                               // 326
                                                                                 // 327
_.extend(ArgumentChecker.prototype, {                                            // 328
  checking: function (value) {                                                   // 329
    var self = this;                                                             // 330
    if (self._checkingOneValue(value))                                           // 331
      return;                                                                    // 332
    // Allow check(arguments, [String]) or check(arguments.slice(1), [String])   // 333
    // or check([foo, bar], [String]) to count... but only if value wasn't       // 334
    // itself an argument.                                                       // 335
    if (_.isArray(value) || _.isArguments(value)) {                              // 336
      _.each(value, _.bind(self._checkingOneValue, self));                       // 337
    }                                                                            // 338
  },                                                                             // 339
  _checkingOneValue: function (value) {                                          // 340
    var self = this;                                                             // 341
    for (var i = 0; i < self.args.length; ++i) {                                 // 342
      // Is this value one of the arguments? (This can have a false positive if  // 343
      // the argument is an interned primitive, but it's still a good enough     // 344
      // check.)                                                                 // 345
      // (NaN is not === to itself, so we have to check specially.)              // 346
      if (value === self.args[i] || (_.isNaN(value) && _.isNaN(self.args[i]))) { // 347
        self.args.splice(i, 1);                                                  // 348
        return true;                                                             // 349
      }                                                                          // 350
    }                                                                            // 351
    return false;                                                                // 352
  },                                                                             // 353
  throwUnlessAllArgumentsHaveBeenChecked: function () {                          // 354
    var self = this;                                                             // 355
    if (!_.isEmpty(self.args))                                                   // 356
      throw new Error("Did not check() all arguments during " +                  // 357
                      self.description);                                         // 358
  }                                                                              // 359
});                                                                              // 360
                                                                                 // 361
var _jsKeywords = ["do", "if", "in", "for", "let", "new", "try", "var", "case",  // 362
  "else", "enum", "eval", "false", "null", "this", "true", "void", "with",       // 363
  "break", "catch", "class", "const", "super", "throw", "while", "yield",        // 364
  "delete", "export", "import", "public", "return", "static", "switch",          // 365
  "typeof", "default", "extends", "finally", "package", "private", "continue",   // 366
  "debugger", "function", "arguments", "interface", "protected", "implements",   // 367
  "instanceof"];                                                                 // 368
                                                                                 // 369
// Assumes the base of path is already escaped properly                          // 370
// returns key + base                                                            // 371
var _prependPath = function (key, base) {                                        // 372
  if ((typeof key) === "number" || key.match(/^[0-9]+$/))                        // 373
    key = "[" + key + "]";                                                       // 374
  else if (!key.match(/^[a-z_$][0-9a-z_$]*$/i) || _.contains(_jsKeywords, key))  // 375
    key = JSON.stringify([key]);                                                 // 376
                                                                                 // 377
  if (base && base[0] !== "[")                                                   // 378
    return key + '.' + base;                                                     // 379
  return key + base;                                                             // 380
};                                                                               // 381
                                                                                 // 382
                                                                                 // 383
///////////////////////////////////////////////////////////////////////////////////

}).call(this);


/* Exports */
if (typeof Package === 'undefined') Package = {};
Package.check = {
  check: check,
  Match: Match
};

})();